您的位置:首页 > 其它

(最小费用最大流)POJ2516 Minimum Cost

2015-07-17 19:42 369 查看
很经典的一道费用流问题,题目大意是有N个商店,M个供应商,供应K种物品,每家商店对每种物品都有一个需求量,每家供应商供应的每种物品的量不同,而每家供应商运送每种物品到一家商店的成本也不一样,求在供等于求和供大于求的情况下供应商满足所有商店需求的最小成本,若供不应求,输出-1。

建图方法如下:

1.建立一个超级源,将其与供应商连接起来,容量为其对一种物品的供应量,代价为0;

2.建立一个超级汇,将其与商店连接起来,容量为商店对一种物品的需求量,代价也为0;

3.供应商与商店之间的边容量为无穷大,代价即供应商运送该物品到商店的成本。

有K种物品,所以要做K次费用流。

判断供不应求的方法:

很简单,每次完成费用流计算后,扫描一次超级汇和商店之间的所有边,若有容量剩余(商店的对某种物品需求量没有得到满足),即供不应求。判断出一次供不应求的情况后,之后的物品只需更新网络容量和代价即可,不需计算费用流,以节省时间。

最小费用流只是在最大流的基础上,在寻找增广路的过程中将增广路的寻找条件变成了寻找源点到汇点的最短路。由于有负权边的存在(这是无法避免的),所以只能采用Bellman-Ford,或其改进算法SPFA,本题采用SPFA。

以下是详细代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
#define INF 20000000

bool vis[105];
int cnt,n,m,result;
int d[105],pre[105],cost[105][105],cap[105][105];
int order[55][55],store[55][55];
queue <int> q;

bool spfa(){
for (int i=1;i<cnt;i++){
d[i]=INF;
vis[i]=false;
}
d[0]=0;
while (!q.empty())
q.pop();
q.push(0);
while (!q.empty()){
int u=q.front();
q.pop();
vis[u]=true;
for (int i=1;i<cnt;i++)
if (cap[u][i] && d[i]>d[u]+cost[u][i]){
d[i]=d[u]+cost[u][i];
pre[i]=u;
if (!vis[i]){
vis[i]=true;
q.push(i);
}
}
vis[u]=false;
}
if (d[1]<INF)
return true;
return false;
}

void costflow(){
int flow=INF;
for (int i=1;i!=0;i=pre[i])
flow=min(flow,cap[pre[i]][i]);
for (int i=1;i!=0;i=pre[i]){
cap[pre[i]][i]-=flow;
cap[i][pre[i]]+=flow;
result+=cost[pre[i]][i]*flow;
}
}

int main(){
int k;
bool flag;
while (scanf("%d%d%d",&n,&m,&k) && (n||m||k)){
flag=true;
cnt=n+m+2;
for (int i=0;i<n;i++)
for (int j=0;j<k;j++)
scanf("%d",&order[i][j]);
for (int i=0;i<m;i++)
for (int j=0;j<k;j++)
scanf("%d",&store[i][j]);
result=0;
for (int t=0;t<k;t++){
memset(cap,0,sizeof(cap));
memset(pre,-1,sizeof(pre));
for (int i=0;i<m;i++){
cap[0][i+2]=store[i][t];
cost[0][i+2]=0;
}
for (int i=0;i<n;i++){
cap[i+m+2][1]=order[i][t];
cost[i+m+2][1]=0;
}
for (int i=0;i<n;i++){
for (int j=0;j<m;j++){
scanf("%d",&cost[2+j][2+m+i]);
cap[2+j][2+m+i]=INF;
cost[2+m+i][2+j]=-cost[2+j][2+m+i];
}
}
if (!flag)
continue;
while (spfa())
costflow();
for (int i=0;i<n;i++){
if (cap[i+m+2][1]>0){
flag=false;
break;
}
}
}
if (flag)
printf("%d\n",result);
else
printf("-1\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  poj 算法