POJ-1584-A Round Peg in a Ground Hole-计算几何-凸多边形+多边形包含圆

来源:互联网 发布:java ssh 远程服务器 编辑:程序博客网 时间:2024/04/30 11:39

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");elseprintf("PEG WILL NOT FIT\n");}}elseprintf("HOLE IS ILL-FORMED\n");}return 0;}


0 0
原创粉丝点击