HDU 2907 Diamond Dealer(凸包对比)
http://acm.hdu.edu.cn/showproblem.php?pid=2907
题意:
给你一个多边形(可能为凹的),然后要你求该多边形有多少个凹角和凹边.凹边就是构成凹角的边. 原始节点相邻3点不共线.
分析:
首先求出凸包,得到逆时针排序的凸包上的点.
由于原始节点是顺时针排序的,所以逆转原始节点数组.
然后依次对比凸包上的相邻两点,看看凸包上相邻两点在原始节点数组中是否还存在点.
如果存在,那么这就是一个凹角. 假设凸包上相邻两点间存在x个点是不在凸包上的原始节点,那么这个凹角由x+1条凹边构成.
最终换算一下结果输出即可.
AC代码:
#include<iostream> #include<cmath> #include<algorithm> #include<cstdio> #include<cstring> using namespace std; //精度控制 const double eps=1e-10; int dcmp(double x) { if(fabs(x)<eps) return 0; return x<0?-1:1; } //点 struct Point { double x,y; Point(){} Point(double x,double y):x(x),y(y){} bool operator==(const Point &rhs)const { return dcmp(x-rhs.x)==0 && dcmp(y-rhs.y)==0; } bool operator<(const Point &rhs)const { return dcmp(x-rhs.x)<0 || (dcmp(x-rhs.x)==0 && dcmp(y-rhs.x)<0); } }; //相邻 typedef Point Vector; //点-点==向量 Vector operator-(Point A,Point B) { return Vector(A.x-B.x, A.y-B.y); } //叉积 double Cross(Vector A,Vector B) { return A.x*B.y-A.y*B.x; } //求凸包 int ConvexHull(Point *p,int n,Point *ch) { sort(p,p+n); n=unique(p,p+n)-p; int m=0; for(int i=0;i<n;i++) { while(m>1 && Cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0) m--; ch[m++]=p[i]; } int k=m; for(int i=n-2;i>=0;i--) { while(m>k && Cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0) m--; ch[m++]=p[i]; } if(n>1) m--; return m; } const int maxn=30+5; Point p[maxn],ch[maxn]; Point v[maxn];//原始节点 int n,P,Q; int main() { int T; scanf("%d",&T); while(T--) { scanf("%d%d%d",&P,&Q,&n); for(int i=0;i<n;i++) { scanf("%lf%lf",&v[i].x,&v[i].y); p[i]=v[i]; } reverse(v,v+n);//把原始点按逆时针排序 int m=ConvexHull(p,n,ch); //找到原始点v中与ch[0]相同的第一个点序号i int i; for(i=0;i<n;i++) if(ch[0]==v[i]) break; int num1=0;//凹角个数 int num2=0;//凹角边数 //依次判断凸包上的相邻两点间是否存在凹角 for(int j=0;j<m;j++ ) { if(v[i]==ch[j]) i=(i+1)%n;//i循环取点 else //发现凹角 { ++num1;//凹角数+1 while( !(v[i]==ch[j]) )//走到底 { i=(i+1)%n; num2++;//凹边+1 } num2++;//凹边+1 i=(i+1)%n; } } if( !(ch[0]==v[i]) )//凸包上最后1点和第0点间特殊判断 { ++num1; while( !(v[i]==ch[0]) ) { i=(i+1)%n; num2++; } num2++; } int ans=num1*-P+Q*(n-num2); printf("%d\n",ans>0?ans:0 ); } return 0; }