【网络流24题-18】分配问题(BSOI2558)

来源:互联网 发布:嵌入式软件开发课程 编辑:程序博客网 时间:2024/05/01 16:26

【网络流24题-18】分配问题

Description

【问题描述】: 
  有n件工作要分配给n(n<=100)个人做。第i个人做第 j件工作产生的效益为cij。试设计一个将n件工作分配给n个人做的分配方案,使产生的总效益最大。 
【编程任务】: 
  对于给定的n件工作和 n个人,计算最优分配方案和最差分配方案。

Input

  由文件input.txt提供输入数据。文件的第1行有1个正整数 n,表示有 n件工作要分配给 n 个人做。接下来的 n 行中,每行有 n 个整数cij,1≤i≤n,1≤j≤n,表示第 i 个人做第j件工作产生的效益为cij。

Output

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

Sample Input


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

        给出在保证最大流的情况下费用/收益的最大/最小值,可以归纳为最小费用最大流的模型。                                我们可以发先,最大流的一种求法是不断寻找从源点到汇点的路径,当没有新的增广路径时,当前的流量即为最大流量。如果我们不断优先寻找最小费用的增广路,那么最后的最大流就会对应着最小的费用,符合贪心的原理。                                                                                                                                                                                                                       具体处理时,我们用最短路的几种不同算法均可,但考虑到有负权边,还要兼顾到较高效率,SPFA是一种不错的选择。本题的具体建图过程如下:

 

1、从 S 向每个 Xi 连一条容量为 1,费用为 0 的有向边。

2、从每个 Yi向 T 连一条容量为 1,费用为 0 的有向边。

3、从每个 Xi 向每个 Yj 连接一条容量为无穷大,费用为 C[i,j]的有向边。 求最小费用最大流,最小费用流值就是最少运费,求最大费用最大流,最大费用流值就是最多运费。

       当我们求最大费用时,将原图中的费用取反,得到的答案就是最大费用的相反数。

CODE

格式丑陋的蒟蒻代码。。。
#include<iostream>#include<cstring>#include<cstdio>#include<queue>using namespace std;const int inf=0x3f3f3f3f;struct Pipe{int next,to,flow,cost;}pipe[20005];Pipe tg[20005];int h[505],cnt=1;inline void add(int x,int y,int z,int k){pipe[++cnt].to=y;pipe[cnt].next=h[x];h[x]=cnt;pipe[cnt].flow=z;pipe[cnt].cost=k;pipe[++cnt].to=x;pipe[cnt].next=h[y];h[y]=cnt;pipe[cnt].flow=0;pipe[cnt].cost=-k;//反向边的花费与费用相反 return ;}inline int read(){char c;int rec=0;while((c=getchar())<'0'||c>'9');while(c>='0'&&c<='9')rec=rec*10+c-'0',c=getchar();return rec;}int N,n,st,ed;int maxx,minn,ans;int vis[505],dis[505],prep[505],pree[505];inline bool SPFA(int st,int ed){queue<int> q;int i,j,p;memset(prep,0,sizeof(prep));memset(pree,0,sizeof(pree));memset(vis,0,sizeof(vis));memset(dis,0x3f,sizeof(dis));dis[st]=0;q.push(st);vis[st]=1;while(!q.empty()){p=q.front();q.pop();vis[p]=0;for(i=h[p];i;i=pipe[i].next){j=pipe[i].to;if(pipe[i].flow&&dis[j]>dis[p]+pipe[i].cost){dis[j]=dis[p]+pipe[i].cost;prep[j]=p;pree[j]=i;//记录最短路径的节点和边 if(!vis[j]){q.push(j);vis[j]=1;}}}}return dis[ed]<inf;}inline void Adjust(){int i,j,p=inf;for(i=ed;i!=st;i=prep[i]){j=pree[i];p=min(p,pipe[j].flow);}for(i=ed;i!=st;i=prep[i]){j=pree[i];pipe[j].flow-=p;pipe[j^1].flow+=p;}ans+=p*dis[ed];return ;}//根据最短路径更改网络 int main(){N=read();st=0;ed=N*2+1;n=N*2+2;int i,j,x;for(i=1;i<=N;i++)add(st,i,1,0),add(i+N,ed,1,0);for(i=1;i<=N;i++){for(j=1;j<=N;j++){x=read();add(i,j+N,inf,x);}}for(i=1;i<=cnt;i++)tg[i]=pipe[i],tg[i].cost=-tg[i].cost;//储存并取反 ans=0;while(SPFA(st,ed))Adjust();minn=ans;ans=0;for(i=1;i<=cnt;i++)pipe[i]=tg[i];while(SPFA(st,ed))Adjust();maxx=-ans;cout<<minn<<endl<<maxx;return 0;}




0 0
原创粉丝点击