bzoj 1091 裸半面交
2015-05-02 13:38
134 查看
枚举割边的次序,8!种可能
每次割边总为新的平面贡献两个新点(也可能是旧点),两点构成的边即新边,新边距离和就是ans
每次割边总为新的平面贡献两个新点(也可能是旧点),两点构成的边即新边,新边距离和就是ans
#include <map> #include <set> #include <queue> #include <stack> #include <math.h> #include <vector> #include <cstdio> #include <string> #include<string.h> #include <fstream> #include <iostream> #include <algorithm> using namespace std; #define exp 1e-8 #define INF 100000000 #define ll long long #define set(a,b) memset(a,b,sizeof(a)); #define for1(a,b,c) for(int a=1;a<=b;a+=c)//1---(b) #define for0(a,b,c) for(int a=0;a<b;a+=c)//0---(b-1) void bug(string st="bug") {cout<<st<<endl;} template<typename __ll> inline void READ(__ll &m){ __ll x=0,f=1;char ch=getchar(); while(!(ch>='0'&&ch<='9')){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} m=x*f; } template<typename __ll> inline void read(__ll &m){READ(m);} template<typename __ll> inline void read(__ll &m,__ll &a){READ(m);READ(a);} template<typename __ll> inline void read(__ll &m,__ll &a,__ll &b){READ(m);READ(a);READ(b);} //调用solve //多边形的核:多边形内部的某一个集合内的一点,可以观察到多变形的所有地方。核即为这个集合。或者说满足所以条件的一个集合 //ax+by+c>=0 或者ax+by+c<=0 当cnt!=0就有核 //ax+by+c>0 或者ax+by+c<0 当cut完,求出的核的面积!=0即有核,精度要高,1e-16! const int maxn=100; struct dat { double x,y; dat(){} dat(double a,double b) { x=a,y=b; } }; dat point[maxn];int n; //读入所有的点,即边的点 dat p[maxn];int cnt; //保存平面的顶点,储存最终多边形的核的所有顶点 dat curp[maxn];int curcnt; //暂时保存平面顶点的数组 double a,b,c; //均是1---cnt int aa,bb; double ans=INF*1.0,temp=0; void getline(dat x,dat y) //提取出直线方程 { a=y.y-x.y; b=x.x-y.x; c=y.x*x.y-x.x*y.y; } dat intersect(dat x,dat y) //获取直线ax+by+c==0 和点x和y所连直线的交点 { double u=fabs(a*x.x+b*x.y+c); double v=fabs(a*y.x+b*y.y+c); dat ans; ans.x=(x.x*v+y.x*u)/(u+v); ans.y=(x.y*v+y.y*u)/(u+v); return ans; } void cut() //更新p[],p储存的是核的顶点 { dat kk[30]; int kkcnt=0; curcnt=0; for(int i=1;i<=cnt;i++)//枚举现存顶点数 { if(a*p[i].x+b*p[i].y+c>=0) //如果符合条件,放入curp { curp[++curcnt]=p[i]; if(a*p[i].x+b*p[i].y+c==0) kk[kkcnt++]=p[i]; } else //否则p[i]在核的外面,还有两种情况 { if(a*p[i-1].x+b*p[i-1].y+c>0) //p[i-1]在核内部, 此时p[i-1]--p[i]与核必定有交点,交点符合核的条件 kk[kkcnt++]=curp[++curcnt]=intersect(p[i-1],p[i]); //所以交点也需加入核集, if(a*p[i+1].x+b*p[i+1].y+c>0) kk[kkcnt++]=curp[++curcnt]=intersect(p[i+1],p[i]); } } for(int i=1;i<=curcnt;i++) //更新p[] p[i]=curp[i]; p[curcnt+1]=p[1]; //弄成一个环 p[0]=p[curcnt]; cnt=curcnt; temp+=sqrt((kk[0].x-kk[1].x)*(kk[0].x-kk[1].x)+(kk[0].y-kk[1].y)*(kk[0].y-kk[1].y)); } void init()//初始化平面 { cnt=4; p[1]=dat(0,0); p[2]=dat(0,bb*1.0); p[3]=dat(aa*1.0,bb*1.0); p[4]=dat(aa*1.0,0); p[cnt+1]=p[1]; //弄成一个环 p[0]=p[cnt]; } void solve(double r=0) //线段推进r距离 { scanf("%d %d",&aa,&bb); scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%lf%lf",&point[i].x,&point[i].y); point[n+1]=point[1]; //弄成一个环 int num[]={1,2,3,4,5,6,7,8}; do { temp=0.0; init(); for(int i=0;i<n;i++) //枚举每一条边,核中的任何一点能观察所有边的前提是 ax+by+c>=0; { int idx=num[i]; getline(point[idx],point[idx+1]); c-=r*sqrt(a*a+b*b); cut(); //将不符合条件的点去掉,并更新符合的核的顶点集合p } ans=min(ans,temp); }while(next_permutation(num,num+n)); printf("%.3lf\n",ans); } int main() { solve(); return 0; }
相关文章推荐
- bzoj1091: [SCOI2003]切割多边形
- BZOJ 1091([SCOI2003]分割多边形-分割直线)
- bzoj1091[SCOI2003]切割多边形
- bzoj1091: [SCOI2003]切割多边形
- BZOJ 1091([SCOI2003]切割多边形-切割直线)
- 【BZOJ】【1091】【SCOI2003】切割多边形
- 【BZOJ1091】【Scoi2003】切割多边形 计算几何 状压DP
- bzoj1091 切割多边形 枚举&计算几何
- BZOJ 1091([SCOI2003]分割多边形-分割直线)
- [BZOJ 3622]已经没有什么好害怕的了
- 【树链剖分】【树状数组】【最近公共祖先】【块状树】bzoj3631 [JLOI2014]松鼠的新家
- 【HNOI2010】【BZOJ2000】stone 取石头游戏
- bzoj 3657 斐波那契数列(fib.cpp/pas/c/in/out)
- bzoj 4104: [Thu Summer Camp 2015]解密运算
- bzoj 4052: [Cerc2013]Magical GCD
- BZOJ 2120: 数颜色 && 2453: 维护队列 【带修莫队版题【也可以学黄学长分块
- 【BZOJ】1419 Red is Good
- BZOJ 2306 [Ctsc2011] 幸福路径 [期望DP做法]
- 【bzoj1030】[JSOI2007]文本生成器
- [最大流]BZOJ 1711: [Usaco2007 Open]Dining吃饭 题解