码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ2280 : [Poi2011]Plot

时间:2015-08-08 19:41:58      阅读:130      评论:0      收藏:0      [点我收藏+]

标签:

二分答案,转化为判定能否划分成不超过m段,且对每段求最小圆覆盖得到的圆半径不超过mid。

对于当前的i,倍增出一个j,使得[i,i+(1<<j)-1]区间恰好不满足条件,然后在[i+(1<<(j-1))-1,i+(1<<j)-1]区间二分查找最大的t,使得[i,t]满足条件,然后划为一段。

时间复杂度$O(n\log^2n)$。

 

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#define N 100010
using namespace std;
int n,m,i,T=50,cnt,ans[N][2];
double l,r,mid,R,eps=1e-10;
struct P{double x,y;}b[N],a[N],O;
inline double dis(P x,P y){return sqrt((x.x-y.x)*(x.x-y.x)+(x.y-y.y)*(x.y-y.y));}
inline P center(P x,P y,P z){
  double a1=y.x-x.x,b1=y.y-x.y,c1=(a1*a1+b1*b1)/2,a2=z.x-x.x,b2=z.y-x.y,c2=(a2*a2+b2*b2)/2,d=a1*b2-a2*b1;
  return (P){x.x+(c1*b2-c2*b1)/d,x.y+(a1*c2-a2*c1)/d};
}
inline void cal(int l,int r){
  int i,j,k,n=0;
  for(i=l;i<=r;i++)a[n++]=b[i];
  for(i=0;i<n;i++)swap(a[rand()%n],a[i]);
  for(O=a[0],R=0,i=1;i<n;i++)if(dis(a[i],O)>R+eps)for(O=a[i],R=0,j=0;j<i;j++)if(dis(a[j],O)>R+eps)for(O=(P){(a[i].x+a[j].x)/2,(a[i].y+a[j].y)/2},R=dis(O,a[i]),k=0;k<j;k++)if(dis(a[k],O)>R+eps)O=center(a[k],a[j],a[i]),R=dis(O,a[i]);
}
inline bool check(double x){
  int i,j,l,r,mid,t,now=0;
  for(i=1;i<=n;i=t+1){
    for(j=1;i+(1<<j)-1<=n;j++){
      cal(i,i+(1<<j)-1);
      if(R>x+eps)break;
    }
    t=i,l=i+(1<<(j-1))-1,r=i+(1<<j)-1;
    if(r>n)r=n;
    while(l<=r){
      cal(i,mid=(l+r)>>1);
      if(R<x+eps)l=(t=mid)+1;else r=mid-1;
    }
    if((++now)>m)return 0;
  }
  return 1;
}
inline void fin(double x){
  int i,j,l,r,mid,t;
  for(i=1;i<=n;i=t+1){
    for(j=1;i+(1<<j)-1<=n;j++){
      cal(i,i+(1<<j)-1);
      if(R>x+eps)break;
    }
    t=i,l=i+(1<<(j-1))-1,r=i+(1<<j)-1;
    if(r>n)r=n;
    while(l<=r){
      cal(i,mid=(l+r)>>1);
      if(R<x+eps)l=(t=mid)+1;else r=mid-1;
    }
    ans[++cnt][0]=i,ans[cnt][1]=t;
  }
}
int main(){
  scanf("%d%d",&n,&m);
  for(i=1;i<=n;i++)scanf("%lf%lf",&b[i].x,&b[i].y);
  cal(1,n);
  r=R;
  if(m>1)while(T--&&r-l>eps)if(check(mid=(l+r)/2))r=mid;else l=mid;
  printf("%.8f\n",r);
  fin(r);
  printf("%d\n",cnt);
  for(i=1;i<=cnt;i++)cal(ans[i][0],ans[i][1]),printf("%.8f %.8f\n",O.x,O.y);
  return 0;
}

  

BZOJ2280 : [Poi2011]Plot

标签:

原文地址:http://www.cnblogs.com/clrs97/p/4713604.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!