hdu 5784 极角排序+基础应用



链接:戳这里


How Many Triangles

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)

Problem Description
Alice has n points in two-dimensional plane. She wants to know how many different acute triangles they can form. Two triangles are considered different if they differ in at least one point.
 
Input
The input contains multiple test cases.
For each test case, begin with an integer n,
next n lines each contains two integers xi and yi.
3≤n≤2000
0≤xi,yi≤1e9
Any two points will not coincide.
 
Output
For each test case output a line contains an integer.
 
Sample Input
3
1 1
2 2
2 3
3
1 1
2 3
3 2
4
1 1
3 1
4 1
2 3
 
Sample Output
0
1
2
 


题意:

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


思路:

三角形总共有C(n,3)个,对应的 锐角+钝角+直角=总和为3*C(n,3)
假设有x个钝角,y个直角,钝角和直角分别对应两个锐角
那么锐角三角形的数量为:(3*C(n,3)-2*x-x-2*y-y)/3 = C(n,3)-x-y
现在统计有多少个钝角和直角!

枚举三角形的一条边,找出这条边左手边有多少个点能与该组成锐角三角形 O(n*n*logn)

嗯!我现在来扣扣细节。

一条边通过两个点确定,不妨设点a和点b去找符合条件的点c个数。

n-1个点分别与点a构成n-1条向量v[i],极角排序一下。就可以更加方便的找出一条向量v左手边有多少个点满足条件

首先枚举一条向量v,那么能组成锐角三角形的点(假设这个点与点a构成向量w)肯定在v的左手边且夹角<90度

这里一个技巧cross(v,w)=0为两向量共线,dot(v,w)>0为两向量同向

cross(v,w)>0叉积为正则表示w在v的左手边,dot(v,w)向量为正数表示夹角<90度 为0表示90度 为负数表示>90度

然后每次统计有多少向量w与当前向量v夹角>=90,减去就可以了

当然了,最后还需要减去三点共线的,三点共线也就是两向量共线,假设数目为tmp,枚举的时候会重复一次。

减去的时候tmp/2就可以了。  参考了Q神的代码,怒拿一血%%%


代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include <ctime>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<iomanip>
#include<cmath>
#include<bitset>
#define mst(ss,b) memset((ss),(b),sizeof(ss))
///#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long ll;
typedef long double ld;
#define INF (1ll<<60)-1
#define Max 1e9
using namespace std;
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);
    }
}p[2020],v[4020];
/*
三角形总共有C(n,3)个,对应的锐角钝角直角总和为3*C(n,3)
假设有x个钝角,y个直角  钝角和直角分别对应两个锐角
那么锐角三角形的数量为:(3*C(n,3)-2*x-x-2*y-y)/3 = C(n,3)-x-y
统计有多少个钝角和直角!
*/
int main(){
    int n;
    while(scanf("%d",&n)!=EOF){
        for(int i=0;i<n;i++) scanf("%I64d%I64d",&p[i].x,&p[i].y);
        ll ans=1LL*n*(n-1)*(n-2)/6,tmp=0;
        for(int i=0;i<n;i++){
            int tot=0;
            for(int j=0;j<n;j++){
                if(i==j) continue;
                v[tot++]=p[j]-p[i]; /// 向量i->j
            }
            sort(v,v+tot);
            for(int j=0;j<tot;j++) v[j+tot]=v[j];
            ll num=0;
            for(int j=1;j<tot;j++){
                if(v[j-1]*v[j]==0 && (v[j-1]^v[j])>0) num++;
                            ///两条向量共线且同向->三点共线
                else num=0;
                tmp+=num;
            }
            int p1=0,p2=0;
            for(int j=0;j<tot;j++){
                while(p1<=j || (p1<j+tot && v[p1]*v[j]<0 && (v[p1]^v[j])>0)) p1++;/// v[j]左边的锐角个数
                while(p2<=j || (p2<j+tot && v[p2]*v[j]<0))p2++;/// v[j]左边的锐角+钝角+直角个数
                ans-=p2-p1;
            }
        }
        printf("%I64d\n",ans-tmp/2);
    }
    return 0;
}
/*
3
1 1
2 2
2 3
3
1 1
2 3
3 2
4
1 1
3 1
4 1
2 3
*/


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值