HDU_5784_HowManyTriangles(极角排序&&尺取法)

1 篇文章 0 订阅
1 篇文章 0 订阅

How Many Triangles

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 559    Accepted Submission(s): 179


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 .
3n2000
0xi,yi1e9
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
 

Author
ZSTU
 

Source
 

Recommend
wange2014

题意

给出平面上一些点

然后问平面上有多少个锐角三角形


解题思路

如果枚举3个点判断是否都是锐角,方案可行吗?

这样可以跑出答案但是O(N^3)肯定是不行的

不过标程里也写了,这个用来对拍还是蛮不错的


那么思路需要转化下,其实数三角形不如数角方便。

但是直接数所有的锐角数量是不对的

众所周知,直角三角形和钝角三角形也有两个锐角

因此,我们应当数出所有的锐角,钝角和直角。

然后(锐角数量-直角钝角数量*2)/3就可以得到锐角三角形的数量了


怎么数角呢?首先枚举中心(顶点)

然后以顶点为中心极角排序

之后把点再复制一遍,这样方便处理

之后利用尺取法,逐渐的推起始边和末尾边

这里注意要把起始边重边跳掉j

然后判断最后一个能形成锐角的位置k和最后一个能形成钝角的位置l

减下就知道目前状态下能得到的各种角的数目了


题目很仁慈点坐标都是整数

所以这个题目并不涉及精度问题

那不涉及精度问题其实也是问题

这种情形下再用tan2进行极角排序就不如直接用叉积来的方便了

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;

typedef long long LL;
const int M=2005;

struct Point
{
    int x,y;
    Point(int _x = 0,int _y = 0) : x(_x),y(_y) {}
    Point operator+(const Point &a)const
    {
        return Point(x+a.x,y+a.y);
    }
    Point operator-(const Point &a)const
    {
        return Point(x-a.x,y-a.y);
    }
    Point operator=(const Point &a)
    {
        x=a.x;y=a.y;
        return *this;
    }
    void read()
    {
        scanf("%d%d",&x,&y);
    }
    void show()const
    {
        printf("%d %d\n",x,y);
    }
}p_or[M],pn[M*2];
LL det(const Point &a,const Point &b)
{
    return (LL)a.x*b.y-(LL)a.y*b.x;
}
LL dot(const Point &a,const Point &b)
{
    return a.x * 1ll * b.x + a.y * 1ll * b.y;
}

bool polar_cmp(const Point &a,const Point &b)
{
    if((LL)a.y*b.y<=0)
    {
        if(a.y>0||b.y>0) return a.y<b.y;
        if(a.y==0&&b.y==0) return a.x<b.x;
    }
    return det(a,b)>0;
}

int n;
LL ans;
LL naa,noa;//锐角数量,直角钝角数量
void cntaa(int core)//寻找以某点为中心的锐角,钝角直角数量
{
    //cout<<"core "<<core<<endl;
    int nn=n-1;
    for(int i=0,j=0;i<n;i++)
        if(i!=core)
            pn[j++]=p_or[i]-p_or[core];
    sort(pn,pn+nn,polar_cmp);
    for(int i=0;i<nn;i++)
        pn[i+nn]=pn[i];
    //cout<<"sort ok"<<endl;
    int j=0,k=0,l=0;//相同极角的点的位置,锐角极角的位置,钝角极角的位置
    for(int i=0;i<nn;i++)
    {
        while(j<i+nn&&det(pn[i],pn[j])==0&&dot(pn[i],pn[j])>0)
            j++;
        k=max(j,k);
        while(k<i+nn&&det(pn[i],pn[k])>0&&dot(pn[i],pn[k])>0)
            k++;
        l=max(k,l);
        while(l<i+nn&&det(pn[i],pn[l])>0)
            l++;
        naa+=k-j;
        noa+=l-k;
        //cout<<"naa noa "<<naa<<" "<<noa<<endl;
    }
}

int main() {
    //freopen("1.in","r",stdin);
    //freopen("1.out","w",stdout);
    while (scanf("%d",&n)!=EOF)
    {
        for(int i=0;i<n;i++)
            p_or[i].read();
        naa=noa=0;
        for(int i=0;i<n;i++)
        {
            cntaa(i);
        }
        ans=(naa-noa*2)/3;
        printf("%I64d\n",ans);
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值