链接:http://poj.org/problem?id=3335
半平面交求多边形的核,多边形的核是多边形的一个区域,这个区域内的点与整个多边形内的任意一点的连线整个线段都在多边形内部,即对这个区域内的点来说,多边形内的所有点都是可见的。而半平面是说,一个二维空间被一个直线分为了两部分,确定这两部分可以用ax+by+c>=0或者ax+by+c<0来确定。这个是n^2的算法,但是对这道题已经足够了。
View Code
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #define eps 1e-8 6 #define N 105 7 using namespace std; 8 struct point 9 { 10 double x,y; 11 }; 12 point p[N]; 13 point s[N]; 14 point q[N]; 15 int n,size,si; 16 void init() 17 { 18 int i; 19 for(i=1;i<=n;i++) 20 p[i]=s[i]; 21 p[n+1]=p[1]; 22 p[0]=p[n]; 23 size=n; 24 } 25 int sig(double k) 26 { 27 return (k<-eps)?-1:(k>eps); 28 } 29 void getl(point p1,point p2,double &a,double &b,double &c) 30 { 31 a=p2.y-p1.y; 32 b=p1.x-p2.x; 33 c=p2.x*p1.y-p2.y*p1.x; 34 } 35 point intersect(point x,point y,double a,double b,double c) 36 { 37 double u=fabs(a*x.x+b*x.y+c); 38 double v=fabs(a*y.x+b*y.y+c); 39 point temp; 40 temp.x=(x.x*v+y.x*u)/(u+v); 41 temp.y=(x.y*v+y.y*u)/(u+v); 42 return temp; 43 } 44 void cut(double a,double b,double c)//对多边形的每一条边进行切割 45 { 46 int i; 47 si=0; 48 for(i=1;i<=size;i++)//枚举在暂时确定的多边形内,有多少点不在直线的右侧 49 { 50 if(sig(a*p[i].x+b*p[i].y+c)>=0) 51 q[++si]=p[i]; 52 else 53 { 54 if(sig(a*p[i-1].x+b*p[i-1].y+c)>0) 55 q[++si]=intersect(p[i],p[i-1],a,b,c); 56 if(sig(a*p[i+1].x+b*p[i+1].y+c)>0) 57 q[++si]=intersect(p[i],p[i+1],a,b,c); 58 } 59 } 60 for(i=1;i<=si;i++)//更新整个多边形的核 61 p[i]=q[i]; 62 p[0]=p[si]; 63 p[si+1]=p[1]; 64 size=si; 65 //for(i=1;i<=si;i++) 66 //printf("%lf %lf\n",p[i].x,p[i].y); 67 //printf("%lf %lf %lf %d\n",a,b,c,si); 68 } 69 bool solve() 70 { 71 int i; 72 double a,b,c; 73 for(i=1;i<=n;i++) 74 { 75 getl(s[i],s[i+1],a,b,c); 76 cut(a,b,c); 77 } 78 //printf("%d\n",size); 79 if(size)//不存在核 80 return true; 81 return false; 82 } 83 int main() 84 { 85 int t; 86 scanf("%d",&t); 87 int i; 88 while(t--) 89 { 90 scanf("%d",&n); 91 for(i=1;i<=n;i++) 92 scanf("%lf%lf",&s[i].x,&s[i].y); 93 s[n+1]=s[1]; 94 s[0]=s[n]; 95 init(); 96 if(solve()) 97 printf("YES\n"); 98 else 99 printf("NO\n"); 100 } 101 return 0; 102 }