【BZOJ 4819】 4819: [Sdoi2017]新生舞会 (0-1分数规划、二分+KM)
4819: [Sdoi2017]新生舞会
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 601 Solved: 313Description
学校组织了一次新生舞会,Cathy作为经验丰富的老学姐,负责为同学们安排舞伴。有n个男生和n个女生参加舞会买一个男生和一个女生一起跳舞,互为舞伴。Cathy收集了这些同学之间的关系,比如两个人之前认识没计算得出a[i][j] ,表示第i个男生和第j个女生一起跳舞时他们的喜悦程度。Cathy还需要考虑两个人一起跳舞是否方便,比如身高体重差别会不会太大,计算得出 b[i][j],表示第i个男生和第j个女生一起跳舞时的不协调程度。当然,还需要考虑很多其他问题。Cathy想先用一个程序通过a[i][j]和b[i][j]求出一种方案,再手动对方案进行微调。Cathy找到你,希望你帮她写那个程序。一个方案中有n对舞伴,假设没对舞伴的喜悦程度分别是a'1,a'2,...,a'n,假设每对舞伴的不协调程度分别是b'1,b'2,...,b'n。令C=(a'1+a'2+...+a'n)/(b'1+b'2+...+b'n),Cathy希望C值最大。Input
第一行一个整数n。接下来n行,每行n个整数,第i行第j个数表示a[i][j]。接下来n行,每行n个整数,第i行第j个数表示b[i][j]。1<=n<=100,1<=a[i][j],b[i][j]<=10^4Output
一行一个数,表示C的最大值。四舍五入保留6位小数,选手输出的小数需要与标准输出相等Sample Input
3
19 17 16
25 24 23
35 36 31
9 5 6
3 4 2
7 8 9Sample Output
5.357143HINT
Source
【分析】
好吧费用流竟然给过。。。
但是我打KM。。。算练一练吧。。。还是打错了两个地方【要记住下次不要错了啊!!!
就是经典的0-1分数规划
二分答案mid
则$\sum a[i][j]-mid*b[i][j]>=0$,这个用KM做最大费用判断是否大于等于0即可。
然后精度要弄小一点才不会被卡,弄到了1e-10,然后狂T是因为INF不够大,晕。。。
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 #include<cmath> 7 using namespace std; 8 #define Maxn 110 9 const double eps=1e-10; 10 const double INF=1e12; 11 12 double a[Maxn][Maxn],b[Maxn][Maxn]; 13 14 int visx[Maxn],visy[Maxn],match[Maxn]; 15 double slack[Maxn],lx[Maxn],ly[Maxn]; 16 int n; 17 18 bool ffind(double mid,int x,int nt) 19 { 20 visx[x]=nt; 21 for(int y=1;y<=n;y++) if(visy[y]!=nt) 22 { 23 if(fabs(lx[x]+ly[y]-(a[x][y]-mid*b[x][y]))<eps) 24 { 25 visy[y]=nt; 26 if(!match[y]||ffind(mid,match[y],nt)) 27 { 28 match[y]=x; 29 return 1; 30 } 31 } 32 else slack[y]=min(slack[y],lx[x]+ly[y]-(a[x][y]-mid*b[x][y])); 33 } 34 return 0; 35 } 36 37 bool check(double mid) 38 { 39 for(int i=1;i<=n;i++) match[i]=0; 40 for(int i=1;i<=n;i++) 41 { 42 visx[i]=visy[i]=0; 43 lx[i]=-INF;ly[i]=0; 44 for(int j=1;j<=n;j++) lx[i]=max(lx[i],a[i][j]-mid*b[i][j]); 45 }int nt=0; 46 for(int i=1;i<=n;i++) 47 { 48 for(int j=1;j<=n;j++) slack[j]=INF; 49 while(1) 50 { 51 nt++; 52 if(ffind(mid,i,nt)) break; 53 double delta=INF; 54 for(int j=1;j<=n;j++) if(visy[j]!=nt) delta=min(delta,slack[j]); 55 for(int j=1;j<=n;j++) 56 { 57 if(visx[j]==nt) lx[j]-=delta; 58 if(visy[j]==nt) ly[j]+=delta; 59 else if(fabs(INF-slack[j])<eps) slack[j]-=delta; 60 } 61 } 62 } 63 double ans=0; 64 for(int i=1;i<=n;i++) ans+=lx[i]+ly[i]; 65 return ans>=0; 66 } 67 68 int main() 69 { 70 double l=0,r=0; 71 scanf("%d",&n); 72 for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) scanf("%lf",&a[i][j]),r+=a[i][j]; 73 for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) scanf("%lf",&b[i][j]); 74 while(r-l>eps) 75 { 76 double mid=(l+r)/2; 77 if(check(mid)) l=mid; 78 else r=mid; 79 } 80 printf("%.6lf\n",l); 81 return 0; 82 }
2017-04-28 13:21:57