您的位置:首页 > 其它

Hdu 5784 How Many Triangles(极角排序+尺取法)

2017-09-05 20:07 344 查看
题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=5784

思路:

1.锐角三角形总锐角个数=总锐角数-非锐角三角形提供锐角数。则锐角三角形个数=总锐角数/3(即(锐角数-2*(直角+钝角数))/3,每钝角和直角三角形提供两锐角)。

2.枚举每个点p[i],以p[i]为原点,求其他n-1个点与原点组成的向量,按极角(小于0时加2*PI)递增排序。设置三个指针l、r、equ,分别代表第一个直角、第一个平角、第一个非0角的位置。枚举n-1个向量j,由于极角递增,两向量角度即为极角l-极角j,l、r、equ递增则形成的角度也递增(相当于尺取法)。则以点p[i]为顶点的锐角个数为l-equ(所有小于90度的角减去0度的角),钝角个数为r-l(所有小于180度的角减去小于等于90度的角)。

3.当指针l、r、equ旋转一周时(l、r、equ下标超过n-1,但此时所有角度尚未枚举完毕),为了便于求角度(即最后一部分向量与起始部分向量所成角度),枚举之前将所有极角加2*PI复制一遍。

#include<cmath>
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define debug
using namespace std;

const double eps=1e-11;
const double PI=acos(-1.0);
const int maxn=4000+50;

int n;

struct Point
{
double x,y;
Point() {}
Point(double x,double y):x(x),y(y) {}
void read()
{
scanf("%lf%lf",&x,&y);
}
};

typedef Point Vector;

Vector operator - (Vector A,Vector B)
{
return Vector(A.x-B.x,A.y-B.y);
}

int dcmp(double x)
{
if(fabs(x)<eps) return 0;
else return x<0?-1:1;
}

int cnt;
Point p[maxn];
double a[maxn];

int main()
{
#ifdef debu
freopen("in.txt","r",stdin);
#endif // debug
while(scanf("%d",&n)!=EOF)
{
int acute=0,notacute=0;
for(int i=1; i<=n; i++) p[i].read();
for(int i=1; i<=n; i++)
{
cnt=0;
for(int j=1; j<=n; j++)
{
if(i==j)continue;
Vector tmp=p[j]-p[i];
double ang=atan2(tmp.y,tmp.x);
if(ang<0) ang+=2*PI;
a[++cnt]=ang;
}

sort(a+1,a+cnt+1);

for(int j=1;j<=cnt;j++) a[cnt+j]=a[j]+2*PI;

int l=1,r=1,equ=1;

for(int j=1; j<=cnt; j++)
{
while(l<=2*cnt&&dcmp(a[l]-a[j]-PI/2)<0) l++;
while(r<=2*cnt&&dcmp(a[r]-a[j]-PI)<0) r++;
while(equ<=2*cnt&&dcmp(a[equ]-a[j])==0) equ++;

acute+=l-equ;
notacute+=r-l;
}
}

printf("%d\n",(acute-2*notacute)/3);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: