网络流二十四题之十八 —— 分配问题

分配问题


Description

n 件工作要分配给 n 个人做。
i 个人做第 j 件工作产生的效益为 Cij
试设计一个将 n 件工作分配给 n 个人做的分配方案,使产生的总效益最大。
对于给定的 n 件工作和 n 个人,计算最优分配方案和最差分配方案。


Input

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


Output

程序运行结束时,将计算出的最小总效益和最大总效益输出到文件。


Sample Input

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


Sample Output

5
14


Solution

第一次打费用流的题目。
本题建模很容易看出来,就只是加一个源点和汇点。

至于两个要求,就分别求出最小费用流和最大费用流即可。


Code

[cpp]
  1. #include <iostream>  
  2. #include <cstdio>  
  3. #include <cstring>  
  4. #include <queue>  
  5.   
  6. #define INF 0x3f3f3f3f  
  7. #define MAXN (250)  
  8. #define ss 0  
  9. #define tt 220  
  10. #define Min(x,y) ((x)<(y)?(x):(y))  
  11.   
  12. using namespace std;  
  13.   
  14. int n,cnt,ans;  
  15. int head[MAXN],nxt[MAXN*MAXN*2],data[MAXN*MAXN*2],flow[MAXN*MAXN*2],wei[MAXN*MAXN*2];  
  16. int flow2[MAXN*MAXN*2];  
  17. int pre[MAXN],dis[MAXN];  
  18. bool in_stack[MAXN];  
  19. queue<int>q;  
  20.   
  21. void add(int x,int y,int z,int W){  
  22.     nxt[cnt]=head[x];data[cnt]=y;flow[cnt]=z;wei[cnt]=W;head[x]=cnt++;  
  23.     nxt[cnt]=head[y];data[cnt]=x;flow[cnt]=0;wei[cnt]=-W;head[y]=cnt++;   
  24. }  
  25.   
  26. bool BFS1(){  
  27.     memset(dis,0x3f,sizeof dis);  
  28.     dis[ss]=0;in_stack[ss]=true;  
  29.     q.push(ss);pre[ss]=pre[tt]=-1;  
  30.     while(!q.empty()){  
  31.         int now=q.front();q.pop();in_stack[now]=false;  
  32.         for(int i=head[now];i!=-1;i=nxt[i]){  
  33.             if(flow[i]&&dis[data[i]]>dis[now]+wei[i]){  
  34.                 dis[data[i]]=dis[now]+wei[i];  
  35.                 pre[data[i]]=i^1;  
  36.                 if(!in_stack[data[i]]){  
  37.                     in_stack[data[i]]=true;  
  38.                     q.push(data[i]);   
  39.                 }  
  40.             }  
  41.         }  
  42.     }  
  43.     return dis[tt]<INF&&pre[tt]>0;  
  44. }  
  45.   
  46. bool BFS2(){  
  47.     memset(dis,-INF,sizeof dis);  
  48.     dis[ss]=0;in_stack[ss]=true;  
  49.     q.push(ss);pre[ss]=pre[tt]=-1;  
  50.     while(!q.empty()){  
  51.         int now=q.front();q.pop();in_stack[now]=false;  
  52.         for(int i=head[now];i!=-1;i=nxt[i]){  
  53.             if(flow2[i]&&dis[data[i]]<dis[now]+wei[i]){  
  54.                 dis[data[i]]=dis[now]+wei[i];  
  55.                 pre[data[i]]=i^1;  
  56.                 if(!in_stack[data[i]]){  
  57.                     in_stack[data[i]]=true;  
  58.                     q.push(data[i]);   
  59.                 }  
  60.             }  
  61.         }  
  62.     }  
  63.     return pre[tt]>0;  
  64. }  
  65.   
  66. void dfs1(){  
  67.     int Low=INF;  
  68.     for(int i=pre[tt];i!=-1;i=pre[data[i]])Low=Min(Low,flow[i^1]);  
  69.     for(int i=pre[tt];i!=-1;i=pre[data[i]]){flow[i]+=Low;flow[i^1]-=Low;}  
  70. }  
  71.   
  72. void dfs2(){  
  73.     int Low=INF;  
  74.     for(int i=pre[tt];i!=-1;i=pre[data[i]])Low=Min(Low,flow2[i^1]);  
  75.     for(int i=pre[tt];i!=-1;i=pre[data[i]]){flow2[i]+=Low;flow2[i^1]-=Low;}  
  76. }  
  77.   
  78. int main(){  
  79.       
  80.     memset(head,-1,sizeof head);  
  81.           
  82.     scanf(”%d”,&n);  
  83.     for(int i=1;i<=n;i++){  
  84.         add(ss,i,1,0);  
  85.         add(i+n,tt,1,0);  
  86.         for(int j=1;j<=n;j++){  
  87.             int x;scanf(“%d”,&x);  
  88.             add(i,j+n,1,x);  
  89.         }  
  90.     }  
  91.       
  92.     memcpy(flow2,flow,sizeof flow);  
  93.       
  94.     ans=0;  
  95.       
  96.     while(BFS1())dfs1();  
  97.     for(int i=0;i<cnt;i++)if(data[i]>=n+1&&data[i]<=n+n&&!flow[i])ans+=wei[i];  
  98.     printf(”%d\n”,ans);  
  99.       
  100.     ans=0;  
  101.       
  102.     while(BFS2())dfs2();  
  103.     for(int i=0;i<cnt;i++)if(data[i]>=n+1&&data[i]<=n+n&&!flow2[i])ans+=wei[i];  
  104.     printf(”%d\n”,ans);  
  105.       
  106.     return 0;  
  107. }  
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值