您的位置:首页 > 其它

bzoj4246 两个人的星座 计算几何

2016-03-28 19:44 330 查看
据说是合宿系列最难的一题。。。(反正我一题都不会也没什么感觉)

考虑任意一对符合条件的三角形(i,j),一定可以在三角形i和j中找到两对点,这两点的连线段所在直线将这对三角形分割到两个不同的半平面中。即存在两条公切线。

那么我们就可以枚举这条公切线了,也就是O(N^2)枚举,这样可以暴力O(N^3)得到答案;注意到如果,枚举一个定点,然后将剩下的点按与定点连线段所在直线的斜率(极角)排序,那么就可以O(N)扫一遍得到答案了。那么就是O(N^2)的了。注意到一对三角形被重复算了4遍,最后要除以4。

AC代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define pi acos(-1.0)
#define ll long long
using namespace std;

int n,c[2][3],blg[10005];
struct point{ int x,y,c,id; double k; }p[10005];
bool cmp(point x,point y){ return x.k<y.k; }
int main(){
scanf("%d",&n); int i,j,k;
for (i=1; i<=n; i++) scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].c);
for (i=1; i<=n; i++) p[i].id=i;
point o; ll tmp,ans=0;
for (i=1; i<=n; i++){
for (j=1; j<=n; j++) if (p[j].id==i) break;
o=p[j]; k=o.c;
for (j=1; j<=n; j++){
p[j].k=(p[j].id!=i)?atan2(p[j].y-o.y,p[j].x-o.x):1e100;
if (p[j].k<=0) p[j].k+=pi;
}
sort(p+1,p+n+1,cmp);
memset(c,0,sizeof(c));
for (j=1; j<n; j++)
if (p[j].y<o.y || p[j].y==o.y && p[j].x>o.x){
c[0][p[j].c]++; blg[j]=0;
} else{
c[1][p[j].c]++; blg[j]=1;
}
for (j=1; j<n; j++){
c[blg[j]][p[j].c]--; tmp=1;
if (k) tmp*=c[0][0]; if (p[j].c) tmp*=c[1][0];
if (k^1) tmp*=c[0][1]; if (p[j].c^1) tmp*=c[1][1];
if (k^2) tmp*=c[0][2]; if (p[j].c^2) tmp*=c[1][2];
ans+=tmp; tmp=1;
if (k) tmp*=c[1][0]; if (p[j].c) tmp*=c[0][0];
if (k^1) tmp*=c[1][1]; if (p[j].c^1) tmp*=c[0][1];
if (k^2) tmp*=c[1][2]; if (p[j].c^2) tmp*=c[0][2];
ans+=tmp;
blg[j]^=1; c[blg[j]][p[j].c]++;
}
}
printf("%lld\n",ans>>2);
return 0;
}


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