多校 #5 hdu 5784 How Many Triangles

http://acm.hdu.edu.cn/showproblem.php?pid=5784

给定平面上互不相同的n个点,求所有锐角三角形的个数。3<=n<=2000

锐角三角形因为要三个角都是锐角,所以限制条件多。即使枚举一个点,另外两条边用极角排序,也只能维护一个锐角,剩下的两个角难于统计。

但是,如果换一种思路,统计所有直角、钝角以及三点共线的个数 ,问题就简单多了。因为因为只有一个直角或钝角或平角,只需依次对每个点,统计以它为哪一个特殊角的直角、钝角、平角三角形有多少即可。

具体做法是对点i,把所有其它点按极角排序。为保证每个不合法三角形(包括平角三角形)只被统计一次,直角、钝角三角形只在一条边时统计(以i为顶点的两条边,分别逆时针旋转直到碰到另一条边,转的角度小的那一条边。)所以维护k为从边 i-j 以 i 为顶点逆时针旋转小于等于180度的最后一个点,l 为边 i-j 逆时针旋转小于90度的最后一个点。这样l到k之间就都是不合法三角形了。因为k,i,j构成的可以使平角,为了避免平角被算两次,可以强制规定在两种中取某一种计算。

为了操作简便,我是把除了i的n-1个点极角排序后,又在后面复制了一遍,不过角度都加了360度。

这种题如果用double计算可能会出现精度问题,我选择除了极角排序用double外,所有角度的判断均使用long long的点积和叉积判断,绝对不会出现精度问题。

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <string>
  4 #include <cstring>
  5 #include <algorithm>
  6 #include <cmath>
  7 using namespace std;
  8 
  9 const double pi = acos(-1.0);
 10 
 11 struct point {
 12     long long x,y;
 13     point() {}
 14     point(long long xx, long long yy) {
 15         x = xx, y = yy;
 16     }
 17     point operator -(const point &p) const {
 18         return point(x - p.x, y - p.y);
 19     }
 20 }a[2010];
 21 struct sta {
 22     double theta; int id;
 23     sta() {}
 24     sta(double thetaa,int idd) {
 25         theta = thetaa, id = idd;
 26     }
 27     bool operator <(const sta &p2) const {
 28         return theta<p2.theta;
 29     }
 30 }b[4010];
 31 
 32 long long dot(const point &p1, const point &p2)
 33 {
 34     return p1.x*p2.x + p1.y*p2.y;
 35 }
 36 long long det(const point &p1, const point &p2)
 37 {
 38     return p1.x*p2.y - p1.y*p2.x;
 39 }
 40 
 41 int main()
 42 {
 43     int i,j,k,l;
 44     long long ans,cnt,n;
 45     while(cin >> n)
 46     {
 47         
 48         for(i = 1; i<=n; i++)
 49             cin >> a[i].x >> a[i].y;
 50             
 51         ans = (long long)n*(n-1)*(n-2)/6;
 52         
 53         for(i = 1; i<=n; i++)
 54         {
 55             int tot = 0;
 56             cnt = 0;
 57             for(j = 1; j<=n; j++)
 58                 if(j!=i) {
 59                     double theta;
 60                     if(a[j].x==a[i].x)
 61                         theta = (a[j].y>a[i].y? pi*0.5 : pi*1.5);
 62                     else {
 63                         theta = atan2(a[j].y-a[i].y, a[j].x-a[i].x);
 64                         if(theta<0) theta += 2.0*pi;
 65                     }
 66                     b[++tot] = sta(theta, j);
 67                 }
 68             sort(b+1, b+n);
 69             for(j = n; j<=2*n-2; j++)
 70             {
 71                 b[j] = b[j-n+1];
 72                 b[j].theta += 2.0*pi;
 73             }
 74 
 75             long long temp;
 76             for(k = l = j = 1; j<n; j++) {
 77                 
 78                 if(det(a[b[j].id] - a[i], a[b[k].id] - a[i])==0ll
 79                     && dot(a[b[j].id] - a[i], a[b[k].id] - a[i])<0ll
 80                     && k>=n) temp = temp;
 81                 else temp = 0;
 82                 while(b[k+1].theta-b[j].theta < pi+1.0
 83                   && det(a[b[j].id] - a[i], a[b[k+1].id] - a[i])>=0ll) {
 84                     k++;
 85                     if(det(a[b[j].id] - a[i], a[b[k].id] - a[i])==0ll
 86                     && dot(a[b[j].id] - a[i], a[b[k].id] - a[i])<0ll
 87                     && k>=n)
 88                         temp++;
 89                     else temp = 0;
 90                 }
 91                 while(b[l+1].theta-b[j].theta<pi
 92                   && dot(a[b[j].id] - a[i], a[b[l+1].id] - a[i])>0) l++;
 93                 cnt += k-l;
 94                 cnt -= temp;
 95             }
 96             ans -= cnt;
 97         }
 98         cout << ans << endl;
 99     }
100     return 0;
101 }
View Code

 

posted @ 2016-08-02 18:33  lyxxx  阅读(518)  评论(0编辑  收藏  举报