链接:http://poj.org/problem?id=2516
题意:有N个shopkeeper(店主),M个supply places(供应点),每个供应点提供K种货物。
每个店主呢,对每种货物又有不同的数量需求。而每种货物从供应点运输到不同的店主时,所花费的费用也是不同的。
求在满足所有店主的需求的前提下,所需的最小花费;若不能满足,输出“-1”。
做了这个题我才知道,原来自己先前做的都只是最大流,这个才是真正的最小费用最大流(MCMF)啊。哎,恕我无知。
解题思路,copy网上的。K种货物独立来处理,也就是每一种货物都用MCMF来求一下最小费用。
构图:
建立超级源和超级汇,st,ed;
所有供应点与源点连边,容量为供应点的货物储存(只K种中的某一种,因为独立处理),费用为0;
所有店主与汇点连边,容量为店主所需的该种货物的数量,费用为0;
供应点与店主连边,容量为INF,费用为该种货物从该供应点运送至该店主时所需的费用。
#include<cstdio>
#include<cstring>
#include<queue>
#define MAXN 100
#define MAXE 10000
#define INF 0x7fffffff
#define MIN(a,b) a>b?b:a
using namespace std;
int shkp[MAXN][MAXN],supp[MAXN][MAXN],cost[MAXN][MAXN][MAXN];
int head[MAXN],dist[MAXN],vist[MAXN],pre[MAXN],pos[MAXN];
int cnt;
int n,m,k;
int st,ed;
int mincost,maxflow;
struct Edge
{
int to;
int cap;
int cost;
int next;
}edge[MAXE];
void add(int u,int v,int cap,int cost)
{
edge[cnt].to=v;
edge[cnt].cap=cap;
edge[cnt].cost=cost;
edge[cnt].next=head[u];
head[u]=cnt++;
edge[cnt].to=u;
edge[cnt].cap=0;
edge[cnt].cost=-cost;
edge[cnt].next=head[v];
head[v]=cnt++;
}
void MCMF(int st,int ed)
{
int i,u,v;
int aug;
mincost=maxflow=0;
for(;;)
{
memset(vist,0,sizeof(vist));
memset(pre,-1,sizeof(pre));
//memset(dist,INF,sizeof(dist));
//memset赋值时,容易溢出变负数,一晚上错这里了!!!
for(i=0;i<=ed;i++)
dist[i]=INF;
dist[st]=0;
pre[st]=st;
vist[st]=1;
queue<int> q;
q.push(st);
while(!q.empty())
{
u=q.front();
q.pop();
vist[u]=0;
for(i=head[u];i!=-1;i=edge[i].next)
{
v=edge[i].to;
if(edge[i].cap>0&&dist[v]>dist[u]+edge[i].cost)
{
dist[v]=dist[u]+edge[i].cost;
pre[v]=u;
pos[v]=i;
if(!vist[v])
{
vist[v]=1;
q.push(v);
}
}
}
}
//if(pre[ed]==-1)
if(dist[ed]==INF) //这两个条件是等价的
break;
aug=INF;
for(u=ed;u!=st;u=pre[u])
aug=MIN(aug,edge[pos[u]].cap);
maxflow+=aug;
mincost+=dist[ed]*aug;
for(u=ed;u!=st;u=pre[u])
{
edge[pos[u]].cap-=aug;
edge[pos[u]^1].cap+=aug;
}
}
}
int main()
{
int i,j,r;
int need,totalcost,totalflow;
while(scanf("%d%d%d",&n,&m,&k)!=EOF)
{
if(!n&&!m&&!k)
return 0;
need=0;
totalcost=0;
totalflow=0;
for(i=1;i<=n;i++)
for(j=1;j<=k;j++)
{
scanf("%d",&shkp[i][j]);
need+=shkp[i][j];
}
for(i=1;i<=m;i++)
for(j=1;j<=k;j++)
scanf("%d",&supp[i][j]);
for(r=1;r<=k;r++)
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
scanf("%d",&cost[r][i][j]);
for(r=1;r<=k;r++)
{
cnt=0;
memset(head,-1,sizeof(head));
for(i=1;i<=m;i++)
add(0,i,supp[i][r],0);
for(i=1;i<=n;i++)
add(i+m,m+n+1,shkp[i][r],0);
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
add(j,i+m,INF,cost[r][i][j]);
st=0;
ed=n+m+1;
MCMF(st,ed);
totalcost+=mincost;
totalflow+=maxflow;
}
if(totalflow!=need)
totalcost=-1;
printf("%d\n",totalcost);
}
return 0;
}