您的位置:首页 > 其它

2016.08.07计算几何总结测试day2

2016-08-09 08:54 148 查看
T1 bzoj: [Usaco2010 OPen]Triangle Counting 数三角形

看到这个题n那么大, 于是想到极角排序搞一搞,然而排完序后立马懵逼,完全不知道接下来应该怎么写。。。。

盯了好久题目给的图后全无思路于是手绘图,然后我就发现了秘密。。。。

极角排序后,如果两个点能与另外的某一个点构成黄金三角形,那么那个点必然在这两个点与原点连线的延长线所夹的区间内。

又因为有极角排序,点a[1],a[2]能构成的三角形,换成点a[1],a[3]肯定也可以构成,因为它们的区间一定是包含关系。

于是我们搞出所有a[i],a[i-1]区间内的答案,计算对答案的贡献即可。

正着有i-1个区间包含它,反着有n-i个区间包含它,然后搞一搞就好了。。。

细节什么的参见代码,反正感觉我代码是写丑了,我还算出了j搞了两遍for循环,看他们代码一个个巨短。。。。理应一遍就应该可以了吧。。。。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define maxn 100010
#define inf 2000000
#define double long double
const double eps=1e-9;

int n,m;

struct point{
double x,y,r;
}a[maxn],b[maxn],O;

double sqr(double x){return x*x;}
double dis(point a,point b){return sqr(a.x-b.x)+sqr(a.y-b.y);}

void getcircle(int i,int j){
O.r=dis(b[i],b[j])/4;
O.x=(b[i].x+b[j].x)/2;
O.y=(b[i].y+b[j].y)/2;
}

void getcircle(int i,int j,int k){
double a,c,d,e,f,g;
a=2*(b[i].x-b[j].x);
g=2*(b[i].y-b[j].y);
c=sqr(b[i].x)-sqr(b[j].x)+sqr(b[i].y)-sqr(b[j].y);
d=2*(b[i].x-b[k].x);
e=2*(b[i].y-b[k].y);
f=sqr(b[i].x)-sqr(b[k].x)+sqr(b[i].y)-sqr(b[k].y);
O.x=(c*e-g*f)/(a*e-g*d);
O.y=(c*d-a*f)/(g*d-a*e);
O.r=dis(O,b[i]);
}

bool incircle(int i){
return dis(b[i],O)-O.r<=eps;
}

bool judgecircle(int l,int r,double limit){
//    if (l==r) return 1;
int cnt=0;
for (int i=l;i<=r;i++) b[++cnt]=a[i];
random_shuffle(b+1,b+cnt+1);
getcircle(1,2);
if (O.r>sqr(limit)+eps) return 0;
for (int i=3;i<=cnt;i++)
if (!incircle(i)){
getcircle(1,i);
if (O.r>sqr(limit)+eps) return 0;
for (int j=2;j<i;j++)
if (!incircle(j)){
getcircle(i,j);
if (O.r>sqr(limit)+eps) return 0;
for (int k=1;k<j;k++)
if (!incircle(k)){
getcircle(i,j,k);
if (O.r>sqr(limit)+eps) return 0;
}
}
}
return 1;
}

bool check(double limit){
int pos=0,num=0;
for (int i=1;i<=n;i=pos+1){
int len=1;
while (i+(len<<1)-1<=n && judgecircle(i,i+(len<<1)-1,limit)) len<<=1;
int l=i+len-1,r=min(i+(len*2)-1,n);
while (l<r){
int mid=(l+r)>>1;
if (judgecircle(i,mid+1,limit)) l=mid+1;
else r=mid;
}
pos=r,num++;
if (num>m) return 0;
}
return 1;
}

int main(){
//    freopen("input.txt","r",stdin);
//    freopen("output.txt","w",stdout);
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
scanf("%Lf%Lf",&a[i].x,&a[i].y);
double l=0,r=inf;
while (l+1e-7<=r){
double mid=(l+r)/2;
if (check(mid)) r=mid;
else l=mid;
}
printf("%.6Lf\n",l);
return 0;
}


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