转载请注明出处,谢谢http://blog.csdn.net/acm_cxlove/article/details/7854526 by---cxlove
题目:给出N个点,选出4个点组成凸多边形的有多少种
http://acm.hdu.edu.cn/showproblem.php?pid=3629
C(N,4)的枚举必挂。
哎还是太弱了,看了别人的做法
因为只考虑4个点,凹包的情况是,3个点组成的三角形内部有一个点
那么我们就用所有的情况,减掉凹包
而对于凹包还不好求,可以考虑选出3个点,另外一个点不在三角形内部,也就是三个点在过另外一个点的直线的同侧。那么我们就可以枚举那一个顶点,也就是可能在内部的点。
然后通过其它点的极角排序,找到两端夹角恰好大于pi的情况,那么从中间选出两个点加上端点
还有一些细节需要处理,下面这篇博客说得比较详细
http://blog.sina.com.cn/s/blog_64675f540100ksug.html
#include<iostream> #include<fstream> #include<iomanip> #include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> #include<cmath> #include<set> #include<map> #include<queue> #include<stack> #include<string> #include<vector> #include<ctime> #include<sstream> #include<cassert> #define LL long long #define eps 1e-7 #define zero(a) fabs(a)<eps #define inf 1<<30 #define N 20 #define pi acos(-1.0) #define pb(a) push_back(a) using namespace std; struct Point{ double x,y; }p[700]; int n; double angle[700]; LL cal(int n,int m){ LL ret=1; for(int i=n;i>n-m;i--) ret=(LL)(ret*i); for(int i=1;i<=m;i++) ret/=i; return ret; } int main(){ int t; scanf("%d",&t); while(t--){ scanf("%d",&n); for(int i=0;i<n;i++) scanf("%lf%lf",&p[i].x,&p[i].y); LL ans=cal(n,4)-n*cal(n-1,3); for(int i=0;i<n;i++){ int m=0,k=1; for(int j=0;j<n;j++){ if(i==j) continue; angle[m++]=atan2(p[j].y-p[i].y,p[j].x-p[i].x); if(angle[m-1]<eps) angle[m-1]+=pi; } sort(angle,angle+m); for(int j=m;j<2*m;j++) angle[j]=angle[j-m]+2*pi; for(int j=0;j<m&&k<2*m;j++){ while(k<2*m&&angle[k]-angle[j]<pi) k++; if(k-j-1>1) ans+=cal(k-j-1,2); } } printf("%I64d\n",ans); } return 0; }