您的位置:首页 > 运维架构

【BZOJ】1914: [Usaco2010 OPen]Triangle Counting 数三角形

2017-10-21 08:17 381 查看

【题意】给定坐标系上n个点,求能构成的包含原点的三角形个数,n<=10^5。

【算法】极角排序

【题解】补集思想,三角形个数为C(n,3)-不含原点三角形。

将所有点极角排序。

对于一个点和原点构成的直线,如果选择这个点和直线一侧的两个点就可以构成不含原点的三角形。

每个点只统计半圈,这样扫1~n下来每个点就会被统计若干次和统计若干次,加起来刚好是答案。这也是基环树DP中的惯用套路。

这样只要用双指针找到半圈内有多少点即可,比较一个点是否在直线一侧可以比较直线向量和目标点向量的叉积是否>0。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define ll long long
using namespace std;
const int maxn=100010,eps=1e-8;
int n;
long long ans;
struct point{
ll x,y;double angle;
ll operator *(const point a)const{
return x*a.y-a.x*y;//
}
}a[maxn];
bool cmp(point a,point b){return fabs(a.angle-b.angle)<eps?a.x<b.x:a.angle<b.angle;}
int main(){
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%lld%lld",&a[i].x,&a[i].y);
a[i].angle=atan2(a[i].y,a[i].x);
}
sort(a,a+n,cmp);
int r=1,num=0;ans=0;
for(int i=0;i<n;i++){
while(r!=i&&a[i]*a[r]>=0)r=(r+1)%n,num++;
ans+=1ll*num*(num-1)/2;
num--;
}
printf("%lld",1ll*n*(n-1)*(n-2)/6-ans);
return 0;
}
View Code

注意叉积计算后作为int,不是double。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: