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

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 }

 

posted @ 2017-04-12 17:24  wfj_2048  阅读(563)  评论(3编辑  收藏  举报