zoukankan      html  css  js  c++  java
  • 【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
  • 相关阅读:
    02 树莓派的远程连接
    01 树莓派系统安装
    Python正课110 —— Django入门
    作业7 答案
    作业8
    作业7
    作业6
    文件操作
    字符编码
    基本数据类型之集合
  • 原文地址:https://www.cnblogs.com/BearChild/p/6702933.html
Copyright © 2011-2022 走看看