HDU 5784 (计算几何)

Problem How Many Triangles (HDU 5784)

题目大意

  给定平面上的n个点(n《2000),询问可以组成多少个锐角三角形。

解题分析

  直接统计锐角三角形较困难,考虑问题的反面,统计直角三角形、钝角三角形、平角三角形(暂时这么叫吧QAQ)。

  首先枚举三角形的一个端点A,对其他点进行象限为第一关键字,极角为第二关键字排序。

  然后使用三个指针,进行O(n)的扫描。

  具体做法为用 i 指针指向三角形的第二个端点B。我们可以假想通过平移和旋转,把A点置于平面直角坐标系的原点,把B点置于x轴的正方向。那么可以与AB组成钝角或直角的点就在三四象限或者y轴。

  将 j 指针指向第一象限内可以组成锐角的最靠后的点,将k指针从j + 1 开始扫描至最后一个可以组成钝角的点,然后统计对答案的贡献。

  之后将 i 指针 +1,继续扫描。

  注意一些特殊的情况,可以写个暴力对拍,造点小数据debug。

参考程序

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cmath>
 4 #include <algorithm>
 5 using namespace std;
 6 #define eps 1e-8
 7 
 8 struct P{
 9     long long x,y;
10     int f;
11     friend P operator -(P a,P b){
12         return (P){a.x-b.x,a.y-b.y};
13     }
14 }a[20008],b[20008],S;
15 
16 int n,m;
17 
18 inline long long cross(P a,P b,P c){  //ab X ac
19     return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x);
20 }
21 
22 inline int calc(P a){
23     if (a.x>0 && a.y==0) return 1;
24     if (a.x>0 && a.y>0) return 1;
25     if (a.x==0 && a.y>0) return 2;
26     if (a.x<0 && a.y>0) return 2;
27     if (a.x<0 && a.y==0) return 3;
28     if (a.x<0 && a.y<0) return 3;
29     if (a.x==0 && a.y<0) return 4;
30     if (a.x>0 && a.y<0) return 4;
31 }
32 
33 inline bool cmp(const P a,const P b) {
34     if (a.f<b.f) return true;
35     if (a.f>b.f) return false;
36     long long tmp=cross(S,a,b);
37     if (tmp>0) return true;
38     return false; 
39 }
40 
41 inline bool ok(P a,P b,P c){
42     long long tmp=(b.x-a.x)*(c.x-a.x)+(b.y-a.y)*(c.y-a.y);
43     if (tmp>0) return true;
44     return false;
45 }
46 
47 int main(){
48     while (~scanf("%d",&n)){
49         for (int i=1;i<=n;i++) scanf("%I64d %I64d",&a[i].x,&a[i].y);
50         long long sum=0;
51         for (int ii=1;ii<=n;ii++){
52             S=a[ii]; m=0; 
53             for (int j=1;j<=n;j++)
54                 if (j!=ii) b[++m]=a[j];
55             for (int i=1;i<=m;i++) b[i].f=calc(b[i]-S);
56             sort(b+1,b+m+1,cmp);
57             int i=1,j=1,k=1;
58             while (ok(S,b[i],b[j]) && cross(S,b[i],b[j])>=0 && j<=m) j++;
59             if (j==m+1) continue;
60             j--; k=j+1;
61             while (i<=m)
62             {
63                 if (!ok(S,b[i],b[k])){        
64                     while (!ok(S,b[i],b[k+1]) && k<m) k++;
65                     sum+=k-j;
66                 }
67                 i++;
68                 if (j<i) j=i; 
69                 while (ok(S,b[i],b[j+1]) && cross(S,b[i],b[j+1])>0 && j<m) j++;
70                 if (k<=j) k=j+1;
71                 if (k>m) break;
72             }        
73         }
74         long long p=1ll*n*(n-1)*(n-2)/6;
75         printf("%I64d
",p-sum);
76     }
77 }
View Code
原文地址:https://www.cnblogs.com/rpSebastian/p/5730475.html