http://poj.org/problem?id=1584
题意:顺时针或逆时针的点,让你先判断多边形是否为凸多边形,如果不是输出HOLE IS ILL-FORMED
如果是,判断能不能把一个给定大小和位置的圆完全包含
if (ok)
printf("PEG WILL FIT\n");
else
printf("PEG WILL NOT FIT\n");
1先把点都变成逆时针,
然后判凸,
然后判圆心是否在多边形内,是的话再看是否被包含
#include <cstdio> #include <cmath> #include <cstring> #include <string> #include <algorithm> #include <queue> #include <map> #include <set> #include <vector> #include <iostream> using namespace std; const double pi=acos(-1.0); double eps=1e-5; double tm[5][35]; double max(double a,double b) {return a>b?a:b;} double min(double a,double b) {return a<b?a:b;} struct POINT { double x; double y; POINT(double a=0, double b=0) { x=a; y=b;} //constructor }; struct LINESEG { POINT s; POINT e; LINESEG(POINT a, POINT b) { s=a; e=b;} LINESEG() { } }; struct LINE // 直线的解析方程 a*x+b*y+c=0 为统一表示,约定 a >= 0 { double a; double b; double c; LINE(double d1=1, double d2=-1, double d3=0) {a=d1; b=d2; c=d3;} }; double multiply(POINT sp,POINT ep,POINT op) { return((sp.x-op.x)*(ep.y-op.y)-(ep.x-op.x)*(sp.y-op.y)); } double area_of_polygon(int vcount,POINT polygon[]) { int i; double s; if (vcount<3) return 0; s=polygon[0].y*(polygon[vcount-1].x-polygon[1].x); for (i=1;i<vcount;i++) s+=polygon[i].y*(polygon[(i-1)].x-polygon[(i+1)%vcount].x); return s/2; } // 如果输入顶点按逆时针排列,返回true bool isconterclock(int vcount,POINT polygon[]) { return area_of_polygon(vcount,polygon)>0; } void checkconvex(int vcount,POINT polygon[],bool bc[]) { int i,index=0; POINT tp=polygon[0]; for(i=1;i<vcount;i++) // 寻找第一个凸顶点 { if(polygon[i].y<tp.y||(fabs(polygon[i].y- tp.y)<eps&&polygon[i].x<tp.x)) { tp=polygon[i]; index=i; } } int count=vcount-1; bc[index]=1; while(count) // 判断凸凹性 { if(multiply(polygon[(index+1)%vcount],polygon[(index+2)%vcount],polygon[index%vcount])>=0 ) bc[(index+1)%vcount]=1; else bc[(index+1)%vcount]=0; index++; count--; } } bool isconvex(int vcount,POINT polygon[]) { bool bc[1005]; checkconvex(vcount,polygon,bc); for(int i=0;i<vcount;i++) // 逐一检查顶点,是否全部是凸顶点 if(!bc[i]) return false; return true; } /* 求点p到线段l的最短距离,并返回线段上距该点最近的点np 注意:np是线段l上到点p最近的点,不一定是垂足 */ double dist(POINT p1,POINT p2) // 返回两点之间欧氏距离 { return( sqrt( (p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y) ) ); } double dotmultiply(POINT p1,POINT p2,POINT p0) { return ((p1.x-p0.x)*(p2.x-p0.x)+(p1.y-p0.y)*(p2.y-p0.y)); } double relation(POINT p,LINESEG l) { LINESEG tl; tl.s=l.s; tl.e=p; return dotmultiply(tl.e,l.e,l.s)/(dist(l.s,l.e)*dist(l.s,l.e)); } // 求点C到线段AB所在直线的垂足 P POINT perpendicular(POINT p,LINESEG l) { double r=relation(p,l); POINT tp; tp.x=l.s.x+r*(l.e.x-l.s.x); tp.y=l.s.y+r*(l.e.y-l.s.y); return tp; } double ptolinesegdist(POINT p,LINESEG l,POINT &np) { double r=relation(p,l); if(r<0) { np=l.s; return dist(p,l.s); } if(r>1) { np=l.e; return dist(p,l.e); } np=perpendicular(p,l); return dist(p,np); } /* 计算点到折线集的最近距离,并返回最近点. 注意:调用的是ptolineseg()函数 */ double ptopointset(int vcount,POINT pointset[],POINT p,POINT &q) { int i; double cd=double(2147483647),td; LINESEG l; POINT tq,cq; for(i=0;i<vcount-1;i++) { l.s=pointset[i]; l.e=pointset[i+1]; td=ptolinesegdist(p,l,tq); if(td<cd) { cd=td; cq=tq; } } q=cq; return cd; } /* 判断圆是否在多边形内.ptolineseg()函数的应用2 */ bool CircleInsidePolygon(int vcount,POINT center,double radius,POINT polygon[]) { POINT q; double d; q.x=0; q.y=0; d=ptopointset(vcount,polygon,center,q); if(d<radius||fabs(d-radius)<eps) return false; else return true; } bool online(LINESEG l,POINT p) { return( fabs(multiply(l.e,p,l.s))<eps &&( ( (p.x-l.s.x)*(p.x-l.e.x)<=0 ) &&( (p.y-l.s.y)*(p.y-l.e.y)<=0 ) ) ); } bool intersect(LINESEG u,LINESEG v) { return( (max(u.s.x,u.e.x)>=min(v.s.x,v.e.x))&& //排斥实验 (max(v.s.x,v.e.x)>=min(u.s.x,u.e.x))&& (max(u.s.y,u.e.y)>=min(v.s.y,v.e.y))&& (max(v.s.y,v.e.y)>=min(u.s.y,u.e.y))&& (multiply(v.s,u.e,u.s)*multiply(u.e,v.e,u.s)>=0)&& //跨立实验 (multiply(u.s,v.e,v.s)*multiply(v.e,u.e,v.s)>=0)); } // (线段u和v相交)&&(交点不是双方的端点) 时返回true bool intersect_A(LINESEG u,LINESEG v) { return ((intersect(u,v))&& (!online(u,v.s))&& (!online(u,v.e))&& (!online(v,u.e))&& (!online(v,u.s))); } int insidepolygon(int vcount,POINT Polygon[],POINT q) { int c=0,i,n; LINESEG l1,l2; bool bintersect_a,bonline1,bonline2,bonline3; double r1,r2; l1.s=q; l1.e=q; l1.e.x=double(2147483647); n=vcount; for (i=0;i<vcount;i++) { l2.s=Polygon[i]; l2.e=Polygon[(i+1)%n]; if(online(l2,q)) return 1; // 如果点在边上,返回1 if ( (bintersect_a=intersect_A(l1,l2))|| // 相交且不在端点 ( (bonline1=online(l1,Polygon[(i+1)%n]))&& // 第二个端点在射线上 ( (!(bonline2=online(l1,Polygon[(i+2)%n])))&& /* 前一个端点和后一个端点在射线两侧 */ ((r1=multiply(Polygon[i],Polygon[(i+1)%n],l1.s)*multiply(Polygon[(i+1)%n],Polygon[(i+2)%n],l1.s))>0) || (bonline3=online(l1,Polygon[(i+2)%n]))&& /* 下一条边是水平线,前一个端点和后一个端点在射线两侧 */ ((r2=multiply(Polygon[i],Polygon[(i+2)%n],l1.s)*multiply(Polygon[(i+2)%n], Polygon[(i+3)%n],l1.s))>0) ) ) ) c++; } if(c%2 == 1) return 0; else return 2; } POINT p[1005]; int main() { int i,j,k; int n; double r,x,y; while(cin>>n>>r>>x>>y) { if (n<3) break; double xx,yy; for (i=0;i<n;i++) { scanf("%lf%lf",&xx,&yy); p[i].x=xx; p[i].y=yy; } if (isconterclock(n,p)==false) //先把点集变成逆时针 { POINT TMP; for (i=0;i<n/2;i++) { TMP=p[i]; p[i]=p[n-i-1]; p[n-i-1]=TMP; } } bool flag=isconvex(n,p); //判断是否多边形 if (flag) { POINT q(x,y); bool ok=CircleInsidePolygon(n,q,r,p); //判断圆是否被包含,这里的判断方法是圆心到各边的距离中的最小值是否大于等于半径 if (insidepolygon(n,p,q)!=0) //所以需要先判断圆心是否被包含 printf("PEG WILL NOT FIT\n"); else { if (ok) printf("PEG WILL FIT\n"); else printf("PEG WILL NOT FIT\n"); } } else printf("HOLE IS ILL-FORMED\n"); } return 0; }