HDU 5784- How Many Triangles-计算几何-two-pointer-数锐角三角形个数



题意:

平面上n个点,问能组成多少个锐角三角形


枚举每个点作为三角形的一个点i,然后对剩下的点计较排序,

以点i与另一个点j 为一条边,去扫描边【i-j】左边有多少个锐角记p1,

再扫描左边一共可以构成多少锐角,钝角,直角,两者相减就是钝角直角的数量p2


每次on扫描的话,总复杂度n^3会超时,可以用two-pointer维护,因为j转移到j+1时,锐角的数量可以在j的基础继续统计,同理,总的角数p2也可以再前者基础上继续统计,那样总的复杂度就是n^2

还有一层排序,所以应该是n^2 logn



</pre><pre name="code" class="cpp">#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
#include <queue>
#include <map>
#include <set>
#include <vector>
using namespace std;
typedef long long  ll;

const int  maxn=2000+50;
const double eps=1e-8;
const double PI=acos(-1.0);
struct point
{
    ll x,y;
    point(ll x=0,ll y=0):x(x),y(y) {}
    point operator - (const point &t)const
    {
        return point(x-t.x,y-t.y);
    }
    ll operator * (const point &t)const  /// 叉积 : 有向面积
    {
        return x*t.y-y*t.x;
    }
    ll operator ^ (const point &t)const  /// 点积 : 有向长度
    {
        return x*t.x+y*t.y;
    }
    bool operator < (const point &t)const  /// 极角排序
    {
        bool up[2]= {0,0};
        if(y>0 || (y==0 && x>0)) up[0]=1;
        if(t.y>0 || (t.y==0 && t.x>0)) up[1]=1;
        if(up[0]^up[1]) return up[0];
        return (*this)*t ? (*this)*t>0 : ((*this)^(*this))<(t^t);
    }
};

point p[maxn],v[maxn*2];
int main()
{

    int n;
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=1; i<=n; i++)
            scanf("%lld%lld",&p[i].x,&p[i].y);
        ll ans=1LL*n*(n-1)*(n-2)/6,tmp=0;
        for(int i=1; i<=n; i++)
        {
            int cun=0;
            for(int j=1; j<=n; j++)
            {
                if(i==j) continue;
                v[++cun]=p[j]-p[i]; /// 向量i->j
            }
            sort(v+1,v+1+cun);
            for(int j=1; j<=cun; j++) v[j+cun]=v[j];

            ///两条向量共线且同向->三点共线,计算会重复2次
            for(int j=2; j<=cun; j++)
            {
                ll num=0;
                while(j<=cun&&v[j-1]*v[j]==0 && (v[j-1]^v[j])>0)
                    j++,num++;
                    num++;
                    tmp+=num*(num-1)/2;
            }
            int p1=1,p2=1;
            for(int j=1; j<=cun; j++)
            {
                while(p1<=j || (p1<j+cun && v[p1]*v[j]<0 && (v[p1]^v[j])>0)) p1++;/// v[j]左边的锐角个数
                while(p2<=j || (p2<j+cun && v[p2]*v[j]<0))p2++;/// v[j]左边的锐角+钝角+直角个数
                ans-=p2-p1;
            }
        }
        printf("%lld\n",ans-tmp/2);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值