bzoj2663: [Beijing wc2012]灵魂宝石(二分+匈牙利)
2663: [Beijing wc2012]灵魂宝石
题目:传送门
题解:
又是一道卡精度的题目。
很容易就可以看出单调性啊,如果R越大,选的人就越多,R越小,选的人就越少。
那最小值就直接搞咯。
那么对于最大值...n==k肯定就是无限大啦
否则的话...有点恶心...太菜了
我们换个角度想问题,因为要知道R的最大值,那么在只能选择k个人的情况下,我们只需要知道n-k个人的最大匹配的最小R值就好。
那么反过来,原本是距离<R时建边,现在就改为距离>=R时再建边。。。
精度1e-7...
代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<cstdlib> 4 #include<cmath> 5 #include<algorithm> 6 #define eps 1e-7 7 using namespace std; 8 struct node 9 { 10 double x,y,next; 11 }a[25000];int len,last[25000]; 12 void ins(int x,int y) 13 { 14 len++;a[len].x=x;a[len].y=y; 15 a[len].next=last[x];last[x]=len; 16 } 17 int match[25000],chw[25000],t; 18 bool findmuniu(int x) 19 { 20 for(int k=last[x];k;k=a[k].next) 21 { 22 int y=a[k].y; 23 if(chw[y]!=t) 24 { 25 chw[y]=t; 26 if(match[y]==0 || findmuniu(match[y])) 27 { 28 match[y]=x; 29 return true; 30 } 31 } 32 } 33 return false; 34 } 35 struct dian 36 { 37 double x,y; 38 }b[25000]; 39 struct bs 40 { 41 double x,y; 42 }c[25000]; 43 int n,k; 44 double dis(double x1,double y1,double x2,double y2){return sqrt(abs((x1-x2)*(x1-x2))+abs((y1-y2)*(y1-y2)));} 45 int check(double R,int opt) 46 { 47 int ans=0; 48 len=0;memset(last,0,sizeof(last)); 49 if(opt==1) 50 { 51 for(int i=1;i<=n;i++) 52 for(int j=1;j<=n;j++) 53 if(dis(b[i].x,b[i].y,c[j].x,c[j].y)<R) 54 ins(i,j+n); 55 memset(match,0,sizeof(match)); 56 memset(chw,0,sizeof(chw));t=0;ans=0; 57 for(int i=1;i<=n;i++) 58 { 59 t++; 60 if(findmuniu(i)) 61 ans++; 62 } 63 } 64 else 65 { 66 for(int i=1;i<=n;i++) 67 for(int j=1;j<=n;j++) 68 if(dis(b[i].x,b[i].y,c[j].x,c[j].y)>=R) 69 ins(i,j+n); 70 memset(match,0,sizeof(match)); 71 memset(chw,0,sizeof(chw));t=0;ans=0; 72 for(int i=1;i<=n;i++) 73 { 74 t++; 75 if(findmuniu(i)) 76 ans++; 77 } 78 } 79 return ans; 80 } 81 int main() 82 { 83 scanf("%d%d",&n,&k); 84 for(int i=1;i<=n;i++)scanf("%lf%lf",&b[i].x,&b[i].y); 85 for(int i=1;i<=n;i++)scanf("%lf%lf",&c[i].x,&c[i].y); 86 double l=0.0,r=999999999.9,ans; 87 while(r-l>=eps) 88 { 89 double mid=(l+r)/2.0; 90 int tt=check(mid,1); 91 if(tt==k)ans=mid; 92 if(tt>=k)r=mid-eps; 93 else l=mid+eps; 94 } 95 printf("%.2lf\n",ans); 96 if(n==k){printf("+INF\n");return 0;} 97 l=0.0,r=999999999.9,ans=0.0; 98 while(r-l>=eps) 99 { 100 double mid=(l+r)/2.0; 101 int tt=check(mid,2); 102 if(tt==n-k)ans=mid; 103 if(tt<n-k)r=mid-eps; 104 else l=mid+eps; 105 } 106 printf("%.2lf\n",ans); 107 return 0; 108 }