bzoj4819 [Sdoi2017]新生舞会
Description
学校组织了一次新生舞会,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^4
Output
一行一个数,表示C的最大值。四舍五入保留6位小数,选手输出的小数需要与标准输出相等
Sample Input
3
19 17 16
25 24 23
35 36 31
9 5 6
3 4 2
7 8 9
19 17 16
25 24 23
35 36 31
9 5 6
3 4 2
7 8 9
Sample Output
5.357143
正解:$01$分数规划+费用流。
好吧其实这题正解好像是$KM$算法,不过忘记写了。。
这是一道经典的$01$分数规划的问题,要解决这类问题,我们首先考虑二分答案。
如果$\frac{\sum_{i=1}^{n}a^{'}i}{\sum_{i=1}^{n}b^{'}i}>mid$
即$\sum_{i=1}^{n}a^{'}i>mid\sum_{i=1}^{n}b^{'}i$
$\sum_{i=1}^{n}a^{'}i-mid*b^{'}i>0$,那么$ans$就会更大。
所以我们每次跑费用流的费用就是$a[i][j]-mid*b[i][j]$,我们要求出这个图的最大费用最大流,那么我们把费用取反就行了。
然后我们判断这个费用是否可行,再二分就行了。实数二分,$eps$大概取$10^{-7}$吧。。
1 //It is made by wfj_2048~ 2 #include <algorithm> 3 #include <iostream> 4 #include <complex> 5 #include <cstring> 6 #include <cstdlib> 7 #include <cstdio> 8 #include <vector> 9 #include <cmath> 10 #include <queue> 11 #include <stack> 12 #include <map> 13 #include <set> 14 #define inf (1e18) 15 #define eps (1e-7) 16 #define N (510) 17 #define il inline 18 #define RG register 19 #define ll long long 20 #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout) 21 22 using namespace std; 23 24 struct edge{ 25 int nt,to,flow,cap; 26 double dis; 27 }g[200010]; 28 29 int head[N],f[N],vis[N],fa[N],p[N],a[N][N],b[N][N],q[1000010],S,T,n,num,flow; 30 double dis[N],cost,ans; 31 32 il int gi(){ 33 RG int x=0,q=1; RG char ch=getchar(); 34 while ((ch<'0' || ch>'9') && ch!='-') ch=getchar(); 35 if (ch=='-') q=-1,ch=getchar(); 36 while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); 37 return q*x; 38 } 39 40 il void insert(RG int from,RG int to,RG int cap,RG double cost){ 41 g[++num]=(edge){head[from],to,0,cap,cost},head[from]=num; return; 42 } 43 44 il int bfs(RG int S,RG int T){ 45 for (RG int i=1;i<=T;++i) dis[i]=inf; 46 RG int h=0,t=1; q[t]=S,dis[S]=0,f[S]=1<<30,vis[S]=1; 47 while (h<t){ 48 RG int x=q[++h],v; 49 for (RG int i=head[x];i;i=g[i].nt){ 50 v=g[i].to; 51 if (dis[v]>dis[x]+g[i].dis && g[i].cap>g[i].flow){ 52 dis[v]=dis[x]+g[i].dis,fa[v]=x,p[v]=i; 53 f[v]=min(f[x],g[i].cap-g[i].flow); 54 if (!vis[v]) vis[v]=1,q[++t]=v; 55 } 56 } 57 vis[x]=0; 58 } 59 if (fabs(dis[T]-inf)<eps) return 0; 60 flow+=f[T],cost+=f[T]*dis[T]; 61 for (RG int i=T;i!=S;i=fa[i]) 62 g[p[i]].flow+=f[T],g[p[i]^1].flow-=f[T]; 63 return 1; 64 } 65 66 il int check(RG double key){ 67 RG double res; memset(head,0,sizeof(head)),num=1; 68 for (RG int i=1;i<=n;++i){ 69 insert(S,i,1,0),insert(i,S,0,0); 70 insert(n+i,T,1,0),insert(T,n+i,0,0); 71 } 72 for (RG int i=1;i<=n;++i) 73 for (RG int j=1;j<=n;++j){ 74 res=a[i][j]-key*b[i][j]; 75 insert(i,n+j,1,-res),insert(n+j,i,0,res); 76 } 77 flow=cost=0; while (bfs(S,T)); return cost<eps; 78 } 79 80 il void work(){ 81 n=gi(),S=2*n+1,T=2*n+2; 82 for (RG int i=1;i<=n;++i) 83 for (RG int j=1;j<=n;++j) a[i][j]=gi(); 84 for (RG int i=1;i<=n;++i) 85 for (RG int j=1;j<=n;++j) b[i][j]=gi(); 86 RG double l=0.0,r=100000.0,mid; 87 while (fabs(r-l)>eps){ 88 mid=(l+r)/2; 89 if (check(mid)) ans=mid,l=mid; else r=mid; 90 } 91 printf("%0.6lf",ans); return; 92 } 93 94 int main(){ 95 File("ball"); 96 work(); 97 return 0; 98 }