HDU 3629 极角排序
题意:
给你n个点(4~700), 问你能够成多少个不同的凸四边形。
题解:
只要求所有凹四边形即可。
对于每个点,凹四边形的个数等于:C(n-1,3)-在这个点同一侧三点构成的三角形的个数。
对于凸多边形的一个顶点,其他顶点必然在穿过这个顶点的直线的同侧。
处理这个有一个好方法,我以前一直没发现。
算极角时,如果是负数(-pi ~ 0),就把它加上2 * pi,这样就把角度统一到了0~2pi。
另外,向这题顺次统计两个点的夹角时,由于会出现转了一圈的情况不好计算角度,所以在原来数组后面再顺次加上n-1一个点,角度同一加2pi
这个方法真的很好用~
View Code
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <cstdlib> 5 #include <algorithm> 6 #include <cmath> 7 8 #define N 22222 9 #define EPS 1e-8 10 11 using namespace std; 12 13 struct PO 14 { 15 double x,y; 16 }p[N]; 17 18 const double PI=acos(-1.0); 19 double ag[N]; 20 int n; 21 22 inline void read() 23 { 24 scanf("%d",&n); 25 for(int i=1;i<=n;i++) scanf("%lf%lf",&p[i].x,&p[i].y); 26 } 27 28 inline int dc(double x) 29 { 30 if(x>EPS) return 1; 31 else if(x<-EPS) return -1; 32 return 0; 33 } 34 35 inline long long c(long long a,long long b) 36 { 37 if(a<b) return 0; 38 long long res=1LL; 39 for(long long i=a;i>=a-b+1;i--) res*=i; 40 for(long long i=b;i>=1;i--) res/=i; 41 return res; 42 } 43 44 inline void go() 45 { 46 long long ans=0; 47 for(int i=1;i<=n;i++) 48 { 49 for(int j=1;j<=n;j++) 50 { 51 if(i==j) continue; 52 double tmp=atan2(p[j].y-p[i].y,p[j].x-p[i].x); 53 if(dc(tmp)<0) tmp+=2*PI; 54 if(j<i) ag[j]=tmp; 55 else ag[j-1]=tmp; 56 } 57 sort(ag+1,ag+n); 58 for(int j=1;j<=n-1;j++) ag[j+n-1]=ag[j]+2*PI; 59 long long res=0; int p2=2; 60 for(int p1=1;p1<=n-1;p1++) 61 { 62 while(fabs(ag[p2]-ag[p1])-PI<0) p2++; 63 res+=c(p2-p1-1,2); 64 } 65 ans+=c(n-1,3)-res; 66 } 67 printf("%I64d\n",c(n,4)-ans); 68 } 69 70 int main() 71 { 72 int cas; scanf("%d",&cas); 73 while(cas--) read(),go(); 74 return 0; 75 }
没有人能阻止我前进的步伐,除了我自己!