【BZOJ4819】【SDOI2017】新生舞会 [费用流][分数规划]

新生舞会

Time Limit: 10 Sec  Memory Limit: 128 MB
[Submit][Status][Discuss]

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]。

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

  1<=n<=100,1<=a[i][j],b[i][j]<=10^4

Main idea

  选择两个人<i,j>会获得A[i][j],以及B[i][j],选择后不能再选,要求使得ΣA[i][j]/ΣB[i][j]最大。

Solution

  最大费用最大流的话,可以把权值取相反数,然后跑最小费用最大流

Code

  1 #include<iostream>  
  2 #include<string>  
  3 #include<algorithm>  
  4 #include<cstdio>  
  5 #include<cstring>  
  6 #include<cstdlib>  
  7 #include<cmath>
  8 using namespace std; 
  9 typedef long long s64;
 10   
 11 const int ONE = 205;
 12 const int EDG = 25005;
 13 const double eps = 1e-6;
 14 const int INF = 21474836;
 15  
 16  
 17 int n,m;
 18 int A[ONE][ONE],B[ONE][ONE];
 19 int next[EDG],first[ONE],go[EDG],from[EDG],pas[EDG],tot;
 20 int vis[ONE],q[1000001],pre[ONE],tou,wei;
 21 double w[EDG],dist[ONE];
 22 int S,T;
 23 double Ans;
 24  
 25 inline int get() 
 26 {
 27         int res=1,Q=1;  char c;
 28         while( (c=getchar())<48 || c>57)
 29         if(c=='-')Q=-1;
 30         if(Q) res=c-48; 
 31         while((c=getchar())>=48 && c<=57) 
 32         res=res*10+c-48; 
 33         return res*Q; 
 34 }
 35  
 36 int Add(int u,int v,int flow,double z)
 37 {
 38         next[++tot]=first[u];   first[u]=tot;   go[tot]=v;  pas[tot]=flow;  w[tot]=z;   from[tot]=u;
 39         next[++tot]=first[v];   first[v]=tot;   go[tot]=u;  pas[tot]=0;     w[tot]=-z;  from[tot]=v;
 40 }
 41  
 42 bool Bfs()
 43 {
 44         for(int i=S;i<=T;i++) dist[i]=INF;
 45         tou = 0;    wei = 1;
 46         q[1] = S;   vis[S] = 1; dist[S] = 0;
 47         while(tou < wei)
 48         {
 49             int u = q[++tou];
 50             for(int e=first[u];e;e=next[e])
 51             {
 52                 int v=go[e];
 53                 if(dist[v] > dist[u]+w[e] && pas[e])
 54                 {
 55                     dist[v] = dist[u]+w[e]; pre[v] = e;
 56                     if(!vis[v])
 57                     {
 58                         q[++wei] = v;
 59                         vis[v] = 1;
 60                     }
 61                 }
 62             }
 63             vis[u] = 0;
 64         }
 65         return dist[T] != INF;
 66 }
 67  
 68 double Deal()
 69 {
 70         int x = INF;
 71         for(int e=pre[T]; go[e]!=S; e=pre[from[e]]) x = min(x,pas[e]);
 72         for(int e=pre[T]; go[e]!=S; e=pre[from[e]])
 73         {
 74             pas[e] -= x;
 75             pas[((e-1)^1)+1] += x;
 76             Ans += w[e]*x;
 77         }
 78 }
 79  
 80 int Check(double ans)
 81 {
 82         memset(first,0,sizeof(first));  tot=0;
 83         S=0;    T=2*n+1;
 84         for(int i=1;i<=n;i++)
 85         {
 86             Add(S,i,1,0);
 87             for(int j=1;j<=n;j++)
 88                 Add(i,j+n, 1,-(A[i][j] - ans*B[i][j]));
 89             Add(i+n,T,1,0);
 90         }
 91          
 92         Ans = 0;
 93         while(Bfs()) Deal();
 94         return -Ans >= eps;
 95 }
 96  
 97 int main()
 98 {
 99         n=get();
100         for(int i=1;i<=n;i++)
101         for(int j=1;j<=n;j++)
102             A[i][j] = get();
103         for(int i=1;i<=n;i++)
104         for(int j=1;j<=n;j++)
105             B[i][j] = get();
106              
107         double l = 0, r = 1e4;
108         while(l < r - 1e-7)
109         {
110             double mid = (l+r)/2.0;
111             if(Check(mid)) l = mid;
112             else r = mid;
113         }
114          
115         if(Check(r)) printf("%.6lf", r);
116         else printf("%.6lf", l);
117 }
View Code

 

posted @ 2017-04-13 11:02  BearChild  阅读(380)  评论(0编辑  收藏  举报