「BZOJ1914」[Usaco2010 OPen] Triangle Counting 数三角形
在一只大灰狼偷偷潜入Farmer Don的牛群被群牛发现后,贝西现在不得不履行着她站岗的职责。从她的守卫塔向下瞭望简直就是一件烦透了的事情。她决定做一些开发智力的小练习,防止她睡着了。想象牧场是一个X,Y平面的网格。她将N只奶牛标记为1…N (1 <= N <= 100,000),每只奶牛的坐标为X_i,Y_i (-100,000 <= X_i <= 100,000;-100,000 <= Y_i <= 100,000; 1 <= i <=N)。然后她脑海里想象着所有可能由奶牛构成的三角形。如果一个三角形完全包含了原点(0,0),那么她称这个三角形为“黄金三角形”。原点不会落在任何一对奶牛的连线上。另外,不会有奶牛在原点。给出奶牛的坐标,计算出有多少个“黄金三角形”。顺便解释一下样例,考虑五只牛,坐标分别为(-5,0), (0,2), (11,2), (-11,-6), (11,-5)。下图是由贝西视角所绘出的图示。
Input
第一行:一个整数: N 第2到第N+1行: 每行两个整数X_i,Y_i,表示每只牛的坐标
Output
* 第一行: 一行包括一个整数,表示“黄金三角形的数量”
Sample Input
5
-5 0
0 2
11 2
-11 -6
11 -5
-5 0
0 2
11 2
-11 -6
11 -5
Sample Output
5
【思路分析】
首先看这道题的条件,要组成一个包括原点的三角形,那么很好这就可以用到几何姿势的极角排序。以样例为准,如下图,共有五个三角形满足条件
于是我们可以以每个点为中心对其他点进行排序,将这个点与原点连一条直线,然后扫一遍,如果选择在这条直线同侧的2个点肯定构成的三角形不会包括原点,对于这道题我们可以直接统计不满足条件的三角形,然后用总数减去不能组成的个数,对于不满足条件的三角形我们会发现,我们只需要找出每个点同侧的所有点然后排列组合就好了。
值得注意的是我们每次只需要统计直线某一边的就好,这样才不会重复统计,我们每次换点后,因为是按极角排序的,所以一定是顺时针或逆时针,换点后下一个点所连直线同侧的点个数一定大于等于上一次的个数减一(模拟思考一下!!!),所以我们就不用每次换点都重新全部寻找了
具体看代码!!!
【代码实现】
1 #include<cstdio> 2 #include<cstring> 3 #include<cmath> 4 #include<algorithm> 5 using namespace std; 6 const int MAXN=1e5+7; 7 struct sd{ 8 long long x,y; 9 double k; 10 bool operator < (const sd &b)const{ 11 return k<b.k; 12 } 13 long long operator *(const sd &b)const{ 14 return x*b.y-y*b.x; 15 } 16 }node[MAXN]; 17 long long read() 18 { 19 long long res=0;int flag=1; 20 char ch=getchar(); 21 while(ch<'0'||ch>'9'){if(ch=='-')flag=-1;ch=getchar();} 22 while(ch>='0'&&ch<='9'){res=res*10+ch-'0';ch=getchar();} 23 return flag*res; 24 } 25 int main() 26 { 27 int n; 28 n=read(); 29 for(int i=1;i<=n;i++) 30 { 31 node[i].x=read(),node[i].y=read(); 32 node[i].k=atan2(node[i].y,node[i].x); 33 } 34 sort(node+1,node+1+n); 35 int r=1,t=0; 36 long long ans=0; 37 for(int i=1;i<=n;i++) 38 { 39 while((r%n+1)!=i&&(node[r%n+1]*node[i])<=0) r++,t++; 40 ans+=(long long)t*(t-1)/2; 41 t--; 42 } 43 printf("%lld",(long long)n*(n-1)*(n-2)/6-ans); 44 return 0; 45 }