• 洛谷 P4014:「分配问题」


    洛谷 P4014:「分配问题」

    题目链接

    题目描述

    有n件工作要分配给n个人做.第i个人做第j件工作产生的效益为Cij .试设计一个将n件工作分配给n个人做的分配方案,使产生的总效益最大.

    输入格式

    文件的第1行有1个正整数n,表示有n件工作要分配给n个人做. 接下来的n行中,每行有n个整数Cij ,表示第i个人做第j件工作产生的效益为Cij .

    输出格式

    两行分别输出最小总效益和最大总效益。

    输入输出样例

    样例输入

    5
    2 2 2 1 2
    2 3 1 2 4
    2 0 1 1 1
    2 3 4 3 3
    3 2 1 2 1

    样例输出

    5
    14

    说明/提示

    1≤ n100 一个人只能修一个工件

    这是一道费用流经典题目

     建图       

    1.设0为超级源点,2*n+1为超级汇点,第i个人的节点为i,第j件工作节点为j+n

    2.从超级源点 向任意 i 属于[1,n] 连接一条容量为1,费用为0的边

    3.从任意 j 属于 [n+1,2*n] 向超级汇点连接一条容量为1,费用为0的边

    4.从任意 i 属于 [1,n]向 任意 j 属于 [n+1,n*2],连接一条容量为1,费用为Ci,j 的边

    做法

    跑一遍最小费用最大流&最大费用最小流,然后再分别输出最小值与最大值 (温馨提醒:一定要输出,不然会WA!)

    为各位大佬献上我丑陋的代码~

      1 #include<bits/stdc++.h>
      2 #define FQ(i,a,b) for(register int i=a;i<=b;i++)
      3 #define prf printf
      4 #define scf scanf
      5 #define ll long long
      6 using namespace std;
      7 const int N=5e4+10;
      8 int INF,n,num=1,ne[N],fi[N],to[N],w[N],pl[N],S,T;
      9 int dst[N],incf[N],P[N],vis[N],ans;
     10 queue<int> q;
     11 void FindMaxN()
     12 {
     13     int fINDmAXn[1];
     14     memset(fINDmAXn,128/2,sizeof(fINDmAXn));    
     15     INF=fINDmAXn[0];
     16 }
     17 ll read()
     18 {
     19     ll x=0,f=1;char ch=getchar();
     20     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
     21     while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
     22     return x*f; 
     23 }
     24 void add(int x,int y,int z,int kl)
     25 {
     26     ne[++num]=fi[x];    
     27     fi[x]=num;    
     28     to[num]=y;   
     29     w[num]=z;
     30     pl[num]=kl; 
     31 }
     32 bool spfa()
     33 { 
     34     for(int i=S;i<=T;i++)dst[i]=INF; 
     35     memset(vis,0,sizeof(vis));  
     36     q.push(S),dst[S]=0; 
     37     incf[S]=1<<30,vis[S]=true;   
     38     while(!q.empty())
     39     {      
     40         int x=q.front();      
     41         vis[x]=false;q.pop();        
     42         for(int i=fi[x];i;i=ne[i])
     43         {            
     44             int ver=to[i];             
     45             if(dst[ver]>dst[x]+pl[i]&&w[i])
     46             {                
     47                 dst[ver]=dst[x]+pl[i];                
     48                 incf[ver]=min(incf[x],w[i]);                
     49                 P[ver]=i;                
     50                 if(!vis[ver])vis[ver]=true,q.push(ver);                 
     51             }             
     52         }    
     53     }
     54     return dst[T]!=INF;  
     55 }
     56 void update()
     57 {   
     58     int x=T;     
     59     while(x!=S)
     60     {         
     61         int i=P[x];         
     62         w[i]-=incf[T];       
     63         w[i^1]+=incf[T];
     64 
     65         x=to[i^1];
     66     }
     67     ans+=dst[T]*incf[T];
     68 }
     69 bool spfa_d()
     70 {
     71     for(int i=S;i<=T;i++)dst[i]=-INF;
     72     q.push(S),dst[S]=0;incf[S]=1<<30;
     73     while(!q.empty())
     74     {
     75         int x=q.front();
     76         vis[x]=false;q.pop();
     77         for(int i=fi[x];i;i=ne[i])
     78         {
     79             int ver=to[i];
     80             if(dst[ver]<dst[x]+pl[i]&&w[i])
     81             {
     82                 dst[ver]=dst[x]+pl[i];
     83                 incf[ver]=min(incf[x],w[i]);
     84                 P[ver]=i;
     85                 if(!vis[ver])vis[ver]=true,q.push(ver);
     86             }
     87         }
     88     }
     89     return dst[T]!=-INF;
     90 }
     91 void update_d()
     92 {
     93     int x=T;
     94     while(x!=S)
     95     {
     96         int i=P[x];
     97         w[i]-=incf[T];
     98         w[i^1]+=incf[T];
     99         x=to[i^1];
    100     }
    101     ans+=dst[T]*incf[T];
    102 }
    103 void add_x(int x,int y,int z,int kl)
    104 {
    105     add(x,y,z,kl);
    106     add(y,x,0,-kl);
    107 }
    108 int main()
    109 {
    110     //freopen(".in","r",stdin);
    111     //freopen(".out","w",stdout);
    112     FindMaxN();
    113     n=read();S=0,T=n*2+1;
    114     for(int i=1;i<=n;i++)
    115     {
    116         for(int j=1;j<=n;j++)
    117         {
    118             int x=read();
    119             add_x(i,j+n,1,x);
    120         }
    121     }
    122     for(int i=1;i<=n;i++)add_x(S,i,1,0),add_x(i+n,T,1,0);
    123     while(spfa())update();
    124     printf("%d
    ",ans);
    125     ans=0;
    126     for(int i=2;i<=num;i+=2)w[i]+=w[i^1],w[i^1]=0;
    127     while(spfa_d())update_d();
    128     printf("%d
    ",ans);
    129     return 0;       
    130 }
    131 //**月雩·薇嫭**

    by:月雩·薇嫭

     

  • 相关阅读:
    糊涂的教授
    有趣的英语角
    聚会
    新年礼物
    三核苷酸
    数字编码
    【同行说技术】iOS程序员从小白到大神必读资料汇总
    【同行说技术】Android图片处理技术资料汇总(一)
    【同行说技术】swift最全学习资料汇集(一)
    【同行说技术】iOS程序员从小白到大神必读资料汇总(一)
  • 原文地址:https://www.cnblogs.com/yueyuweihu/p/12093052.html
Copyright © 2020-2023  润新知