多校 #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 }