您的位置:首页 > 其它

HDU 5784 How Many Triangles(极角排序)

2016-08-21 15:42 351 查看
题意很简单,平面上给你n个点,求锐角三角形的个数,点没有重复

首先就是随便选三个点C(n,3),可能构成锐角,直角,钝角,并且直角钝角都不会重复计算

所以锐角的个数就是C(n,3)−直角−钝角−三点共线

这里用点乘和叉乘来求解直角钝角还有三点共线的问题

首先枚举点,然后对其他点和它构成的向量,做极角排序

然后对一个向量v,找它左边的向量w,如果cross(w,v)<0,表示w在v的左边

然后如果dot(v,w)≤0,表示他们是直角或者钝角

三点共线在排序完之后,看cross(v,w)==0,dot(v,w)>0

细节就是这题每个向量最好要存两遍,求解直角钝角的时候不好写,要用左边的向量个数−左边锐角个数=左边直角钝角个数,然后再减去

直接找一个向量左边直角钝角的范围,不好找

代码:

#include <map>
#include <set>
#include <ctime>
#include <stack>
#include <queue>
#include <cmath>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <sstream>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#pragma comment(linker,"/STACK:102400000,102400000")

using namespace std;
#define   MAX           1000005
#define   MAXN          1000005
#define   maxnode       205
#define   sigma_size    26
#define   lson          l,m,rt<<1
#define   rson          m+1,r,rt<<1|1
#define   lrt           rt<<1
#define   rrt           rt<<1|1
#define   middle        int m=(r+l)>>1
#define   LL            long long
#define   ull           unsigned long long
#define   mem(x,v)      memset(x,v,sizeof(x))
#define   lowbit(x)     (x&-x)
#define   pii           pair<int,int>
#define   bits(a)       __builtin_popcount(a)
#define   mk            make_pair
#define   limit         10000

//const int    prime = 999983;
const int    INF   = 0x3f3f3f3f;
const LL     INFF  = 0x3f3f;
const double pi    = acos(-1.0);
const double inf   = 1e18;
const double eps   = 1e-4;
const LL    mod    = 772002;
const ull    mx    = 133333331;

/*****************************************************/
inline void RI(int &x) {
char c;
while((c=getchar())<'0' || c>'9');
x=c-'0';
while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0';
}
/*****************************************************/

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[MAX],v[MAX*2];

int main(){
//freopen("1002.in","r",stdin);
//freopen("froggy.out","w",stdout);
int n;
while(cin>>n){
for(int i=1;i<=n;i++) scanf("%I64d%I64d",&p[i].x,&p[i].y);
LL ans=(LL)n*(n-1)*(n-2)/6;
LL tmp=0;
for(int i=1;i<=n;i++){
int tot=0;
for(int j=1;j<=n;j++){
if(i==j) continue;
v[tot++]=p[j]-p[i];
}
sort(v,v+tot);
for(int j=0;j<tot;j++) v[j+tot]=v[j];
int num=0;
for(int j=1;j<tot;j++){
if(v[j]*v[j-1]==0&&(v[j]^v[j-1])>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++;//左边并且是锐角
while(p2<=j||(p2<j+tot&&v[p2]*v[j]<0)) p2++;//左边,锐角+钝角+直角
ans-=p2-p1;
}
}
cout<<ans-tmp/2<<endl;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: