hdu 3629 Convex 计算几何

题目描述:给你n个点(4~700), 问你能够成多少个不同的凸四边形。

求出所有凹包的个数,然后用总数C(n, 4)减去凹包的个数,就是答案。

依次枚举每个点i,看看其它点能够成多少个包括点i的三角形,就是以这个点为中心的凹包的个数。

找三角形也要一定的技巧,也是通过逆向思维:找出有多少个三角形不包括点i,然后用总三角形个数C(n – 1, 3) – 以这个点为中心的凹包的个数。

注意到,如果3个点不能圈住中心点,则必然是存在一条通过中心点的直线,使得这三个点都在直线的同侧。利用这个形式,我们用如下方法寻找三角形:

1:以中心点为中心,对剩余n-1个点极角排序。

2:依次处理排序后的n-1个点,对于每一个点i,依次往后扫描,找到第一个点j,是j和i的夹角大于180度。

3:那么点i + 1到点j – 1的所有点都可以和点i构成不包括中心点的三角形。个数是C(j – i – 1, 2)

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
using namespace std;
#define LL long long
#define eps 1e-8
double pi=2*asin(1);

struct point
{
    double x,y;
}p[705];
double A[1705];
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 n,T,i,j;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(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(i=0;i<n;i++)
        {
            int m=0,k=1;
            for(j=0;j<n;j++) //极角排序
            {
                if(i==j) continue;
                A[m++]=atan2(p[j].y-p[i].y,p[j].x-p[i].x);
                if(A[m-1]<eps) A[m-1]+=2*pi;
            }
            sort(A,A+m);
            for(j=m;j<2*m;j++)
                A[j]=A[j-m]+2*pi;
            for(j=0;j<m&&k<2*m;j++)
            {
                while(k<2*m&&A[k]-A[j]<pi) k++;
                if(k-j-1>1) ans+=cal(k-j-1,2);
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}

 

posted on 2016-02-26 21:54  13rj1115  阅读(257)  评论(0编辑  收藏  举报

导航