hdu3629 计算几何

Convex

Time Limit: 10000/4000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1386    Accepted Submission(s): 421

Problem Description
Your task is very simple. You will get the coordinates of n points in a plane. It is guaranteed that there are no three points on a straight line. You can choose any four points from these points to construct a quadrangle. Now, please tell me how many convex quadrangles you can construct.
 
Input
The first line of input contain an integer z (z ≤ 20), indicating the number of test cases. For each test case, the first line contain an integer n (4 ≤ n ≤ 700), indicating the number of points. Each of the next n lines contains two integers x and y (-1000000 ≤ x, y ≤ 1000000), indicating the coordinate of corresponding point.
 
Output
For each test case, just output a single integer, the number of convex quadrangles you can construct.
 
Sample Input
2
4
0 0
0 1
1 0
1 1
4
0 0
1 0
0 1
-1 -1
 
Sample Output
1 0
 
Source
 
题意:给n个点,求任意取四个点组成凸四边形能有多少个?
思路:一开始除了暴力没想到方法,暴力C(700,4)一定超时。
后来看了解题报告才会了,阿门~~~太菜了~~~
很详细的图解释。。。
View Code
 1 #include<cmath>
 2 #include<cstdio>
 3 #include<iostream>
 4 #include<algorithm>
 5 #define eps 1e-8
 6 #define pi acos(-1.0)
 7 using namespace std;
 8 const int N=1000;
 9 struct Point{double x, y;}p[N];
10 double ans[2*N];
11 long long C(int a,int b){
12     long long ans=1;
13     for(int i=0;i<b;i++) ans*=(a-i);
14     for(int i=2;i<=b;i++) ans/=i;
15     return ans;
16 }
17 int main(){
18     int t,n;
19     scanf("%d",&t);
20     while(t--){
21 
22         scanf("%d",&n);
23         for(int i=0;i<n;i++)
24         scanf("%lf%lf",&p[i].x,&p[i].y);
25 
26         long long res=0;
27         for(int i=0;i<n;i++){
28             for(int j=0;j<n;j++){
29                 if(j==i) continue;
30                 double tmp=atan2(p[j].y-p[i].y,p[j].x-p[i].x);
31                 if(tmp<=-eps) tmp+=2*pi;
32                 j<i?ans[j]=tmp:ans[j-1]=tmp;
33             }
34             sort(ans,ans+n-1);
35             int k=1;
36             long long re2=0;
37             for(int j=0;j<n-1;j++)
38                 ans[j+n-1]=ans[j]+2*pi;
39 
40             for(int j=0;j<n-1;j++){
41                 while(fabs(ans[k]-ans[j])-pi<0) k++;
42                 if(k-j-1>=2) re2+=C(k-j-1,2);
43             }
44             res+=C(n-1,3)-re2;
45         }
46         printf("%I64d\n",C(n,4)-res);
47     }
48     return 0;
49 }

 

在C语言的math.h或C++中的cmath中有两个求反正切的函数atan(double x)与atan2(double y,double x)  他们返回的值是弧度 要转化为角度再自己处理下。

前者接受的是一个正切值(直线的斜率)得到夹角,但是由于正切的规律性本可以有两个角度的但它却只返回一个,因为atan的值域是从-90~90 也就是它只处理一四象限,所以一般不用它。

第二个atan2(double y,double x) 其中y代表已知点的Y坐标 同理x ,返回值是此点与远点连线与x轴正方向的夹角,这样它就可以处理四个象限的任意情况了,它的值域相应的也就是-180~180了

posted @ 2012-10-06 21:18  _sunshine  阅读(733)  评论(0编辑  收藏  举报