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)一定超时。
后来看了解题报告才会了,阿门~~~太菜了~~~
很详细的图解释。。。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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了