[HDU 5784] How Many Triangles (几何+极角排序)

HDU - 5784

几何题,给定平面上若干个不重复的点,
求这些点能组成多少个锐角三角形


我刚开始的时候想的是枚举钝角和直角
然后计算每三个点能组成的三角形的个数
减去共线的,再减去钝角和直角的个数,即为答案
而且我在极角排序之后,我试图用二分来确定上下界
这样也不是不能做,但是比较麻烦

题解的方法就比较好
统计锐角的个数,设为 A ,钝角和直角的个数,设为 B
每个锐角三角形有三个锐角,每个钝角和直角三角形均贡献两个锐角
所以答案即为 A2B3
然后题解在对每个点极角排序之后,采用 two pointers的方式来找上下界
比二分好写多了,也很方便,时间复杂度 (N2logN)

统计锐角个数的时候,要考虑和当前枚举的点共线的那些点
顺便精度要开得小一些,要开到 1e-10以上
顺便感谢某周教我如何判精度,输出最小角的atan2
比如这题就是 atan2(1,1e9) = 1e-9,然后大两个级别的精度就行

#pragma comment(linker, "/STACK:102400000,102400000")
#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cctype>
#include <map>
#include <set>
#include <queue>
#include <bitset>
#include <string>
using namespace std;
typedef pair<int,int> Pii;
typedef long long LL;
typedef unsigned long long ULL;
typedef double DBL;
typedef long double LDBL;
#define MST(a,b) memset(a,b,sizeof(a))
#define CLR(a) MST(a,0)
#define SQR(a) ((a)*(a))
#define PCUT puts("----------")

const DBL eps=1e-12, PI=acos(-1.0);
const int maxn=2e3+10;
int sgn(DBL x){return x>eps?1:(x<-eps?(-1):0);}
struct Vector
{
    DBL x,y;
    Vector operator - (const Vector &v) const {return {x-v.x, y-v.y};}
    DBL operator * (const Vector &v) const {return x*v.x + y*v.y;}
    int read() {return scanf("%lf%lf", &x, &y);}
};
typedef Vector Point;

int N;
Point P[maxn];
DBL ang[2*maxn];

int Cnt(DBL);

int main()
{
    #ifdef LOCAL
    freopen("in.txt", "r", stdin);
//  freopen("out.txt", "w", stdout);
    #endif
    printf("%.12f\n", atan2(1,1e9));
    while(~scanf("%d", &N))
    {
        for(int i=0; i<N; i++) P[i].read();
        LL ans = 0, nans=0;
        for(int i=0; i<N; i++)
        {
            Vector L;
            for(int j=i+1; j<i+N; j++)
            {
                int id=j%N;
                L = P[id]-P[i];
                ang[j-i-1] = atan2(L.y, L.x);
            }
            sort(ang, ang+N-1);
            memcpy(ang+N-1, ang, sizeof(DBL)*(N-1));
            for(int j=N-1; j<2*N-2; j++) ang[j] += 2.0*PI;
            int res = Cnt(PI*0.5);
            ans += res;
            nans += Cnt(PI) - res;
        }
        printf("%lld\n", (ans-2*nans)/3);
    }
    return 0;
}

int Cnt(DBL A)
{
    int r=0, res=0;
    for(int l=0; l<N-1; l++)
    {
        int ecnt=0;
        while( sgn(ang[l+ecnt]-ang[l]) == 0) ecnt++;
        l = l+ecnt-1;
        r = max(r, l+1);
        while( r-l+1 <= N-1 && sgn(ang[r]-ang[l] - A) < 0) r++;
        res += (r-l-1)*ecnt;
    }
    return res;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值