Bzoj4819 [Sdoi2017]新生舞会

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 470  Solved: 242

Description

学校组织了一次新生舞会,Cathy作为经验丰富的老学姐,负责为同学们安排舞伴。有n个男生和n个女生参加舞会
买一个男生和一个女生一起跳舞,互为舞伴。Cathy收集了这些同学之间的关系,比如两个人之前认识没计算得出 
a[i][j] ,表示第i个男生和第j个女生一起跳舞时他们的喜悦程度。Cathy还需要考虑两个人一起跳舞是否方便,
比如身高体重差别会不会太大,计算得出 b[i][j],表示第i个男生和第j个女生一起跳舞时的不协调程度。当然,
还需要考虑很多其他问题。Cathy想先用一个程序通过a[i][j]和b[i][j]求出一种方案,再手动对方案进行微调。C
athy找到你,希望你帮她写那个程序。一个方案中有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

HINT

 

Source

 
网络流 实数二分答案 费用流
C=(a'1+a'2+...+a'n)/(b'1+b'2+...+b'n)
为了让C值最大,可以二分找到最大的C使得 $(a'1+a'2+...+a'n)>C(b'1+b'2+...+b'n) $
 
二分费用后建边,跑最大费用最大流,检验最大费用是否为正数。
常数莫名大,自测只能过4个点。好在B站算总时,得以水过
 
  1 /*by SilverN*/
  2 #include<iostream>
  3 #include<algorithm>
  4 #include<cstring>
  5 #include<cstdio>
  6 #include<cmath>
  7 #include<queue>
  8 using namespace std;
  9 const int INF=1e9;
 10 const double eps=1e-7;
 11 const int mxn=100010;
 12 int read(){
 13     int x=0,f=1;char ch=getchar();
 14     while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 15     while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
 16     return x*f;
 17 }
 18 struct edge{
 19     int u,v,nxt,f;
 20     double w;
 21 }e[mxn<<1];
 22 int hd[205],mct=1;
 23 inline void add_edge(int u,int v,int f,double w){
 24     e[++mct].v=v;e[mct].u=u;e[mct].nxt=hd[u];e[mct].f=f;e[mct].w=w;hd[u]=mct;
 25     return;
 26 }
 27 inline void insert(int u,int v,int f,double w){
 28     add_edge(u,v,f,w); add_edge(v,u,0,-w);
 29     return;
 30 }
 31 int n,m,S,T;
 32 int a[105][105],b[105][105];
 33 /*void restore(double cost){
 34     for(register int i=2;i<=mct;i+=2){
 35         if(e[i^1].f){
 36             e[i].f+=e[i^1].f;
 37             e[i^1].f=0;
 38         }
 39         if(e[i].v>n && e[i].v!=T){
 40             double res=a[e[i].u][e[i].v-n]-(double)b[e[i].u][e[i].v-n]*cost;
 41             e[i].w=res;
 42             e[i^1].w=-res;
 43         }
 44     }
 45     return;
 46 }*/
 47 double dis[205];
 48 bool inq[205];
 49 int pre[205];
 50 int q[mxn],hed,tl;
 51 bool SPFA(){
 52     for(int i=S;i<=T;i++)dis[i]=-INF,pre[i]=0;
 53     hed=tl=1;
 54     q[hed]=S;
 55     dis[S]=0;
 56     while(hed<=tl){
 57         int u=q[hed++];
 58         inq[u]=0;
 59         for(int i=hd[u];i;i=e[i].nxt){
 60             int v=e[i].v;
 61             if(e[i].f && dis[v]<dis[u]+e[i].w){
 62                 dis[v]=dis[u]+e[i].w;
 63                 pre[v]=i;
 64                 if(!inq[v]){inq[v]=1;
 65                     q[++tl]=v;
 66                 }
 67             }
 68         }
 69     }
 70     return dis[T]!=-INF;
 71 }
 72 double Res;
 73 inline int min(int a,int b){return a<b?a:b;}
 74 double MCF(){
 75     Res=0;
 76     while(SPFA()){
 77         int tmp=INF;
 78         for(int i=pre[T];i;i=pre[e[i].u])tmp=min(tmp,e[i].f);
 79         for(int i=pre[T];i;i=pre[e[i].u]){
 80             e[i].f-=tmp;
 81             e[i^1].f+=tmp;
 82             Res+=e[i].w*tmp;
 83         }
 84     }
 85     return Res;
 86 }
 87 void Rebuild(double lim){
 88     memset(hd,0,sizeof hd);
 89     mct=1;
 90     S=0;T=2*n+1;
 91     for(int i=1;i<=n;i++){
 92         insert(S,i,1,0);
 93         insert(i+n,T,1,0);
 94         for(int j=1;j<=n;j++)
 95             insert(i,j+n,1,a[i][j]-b[i][j]*lim);
 96     }
 97     return;
 98 }
 99 void solve(){
100     double l=0,r=1e4,ans=0;
101     while(r-l>eps){
102         double mid=(l+r)/2;
103 //        restore(mid);
104         Rebuild(mid);
105         double res=MCF();
106         if(res>0){l=mid;ans=mid;}
107         else r=mid;
108     }
109     printf("%.6f\n",ans);
110 }
111 int main(){
112     int i,j;
113     n=read();
114     for(i=1;i<=n;i++)
115         for(int j=1;j<=n;j++)
116             a[i][j]=read();
117     for(i=1;i<=n;i++)
118         for(int j=1;j<=n;j++)
119             b[i][j]=read();
120     solve();
121     return 0;
122 }

 

 
posted @ 2017-04-19 21:26  SilverNebula  阅读(318)  评论(0编辑  收藏  举报
AmazingCounters.com