您的位置:首页 > 其它

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

2016-08-03 10:49 357 查看

HDU - 5784

几何题,给定平面上若干个不重复的点,

求这些点能组成多少个锐角三角形

我刚开始的时候想的是枚举钝角和直角

然后计算每三个点能组成的三角形的个数

减去共线的,再减去钝角和直角的个数,即为答案

而且我在极角排序之后,我试图用二分来确定上下界

这样也不是不能做,但是比较麻烦

题解的方法就比较好

统计锐角的个数,设为 A,钝角和直角的个数,设为 B

每个锐角三角形有三个锐角,每个钝角和直角三角形均贡献两个锐角

所以答案即为 A−2B3

然后题解在对每个点极角排序之后,采用 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: