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
  • 相关阅读:
    VIJOS-P1340 拯救ice-cream(广搜+优先级队列)
    uva 11754 Code Feat
    uva11426 GCD Extreme(II)
    uvalive 4119 Always an Interger
    POJ 1442 Black Box 优先队列
    2014上海网络赛 HDU 5053 the Sum of Cube
    uvalive 4795 Paperweight
    uvalive 4589 Asteroids
    uvalive 4973 Ardenia
    DP——数字游戏
  • 原文地址:https://www.cnblogs.com/BearChild/p/6702933.html
Copyright © 2011-2022 走看看