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 }
没有人能阻止我前进的步伐,除了我自己!
原文地址:https://www.cnblogs.com/proverbs/p/2937938.html