• 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
    ",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 }
     
  • 相关阅读:
    wpf学习笔记StackPanel
    wpf学习笔记DockPanel
    wpf学习笔记Viewbox
    C#.NET 中的类型转换
    超简单U盘PE启动完全攻略(U盘上仅四个文件)
    Web 应用的 UML 建模与 .NET 框架开发
    100多个很有用的JavaScript函数以及基础写法大集合
    Asp.net(C#)显示所有缓存 清除所有缓存
    grub引导U盘(集成常用工具/深山红叶PE工具箱V30/完美者U盘维护系统V8.1)
    GRUB启动命令详解
  • 原文地址:https://www.cnblogs.com/SilverNebula/p/6735961.html
Copyright © 2020-2023  润新知