题目链接:http://poj.org/problem?id=2516
Description
Input
Output
Sample Input
1 3 3 1 1 1 0 1 1 1 2 2 1 0 1 1 2 3 1 1 1 2 1 1 1 1 1 3 2 20 0 0 0
Sample Output
4 -1
Source
题意:
有N个店主,M个供应商,K种物品。
每个供应商对每种物品的的供应量已知,每个店主对每种物品的需求量的已知,从不同的供应商运送不同的货物到不同的店主手上需要不同的花费,又已知从供应商Mj送第kind种货物的单位数量到店主Ni手上所需的单位花费。
问:供应是否满足需求?如果满足,最小运费是多少?
转:
输入格式
在说解题思路之前,首先说说输入格式,因为本题的输入格式和解题时所构造的图的方向不一致,必须要提及注意。以样例1为例:

PS:
把 k 种物品分开来计算,每次对一种物品进行最小费用最大流计算。
对于每种物品,从源到供应商连接,容量为供应商的储存量,费用为0。
采购商到汇连边,容量为需求量,费用为0。
供应商到采购商连边,容量为无穷,费用为对应的运费。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
const int MAXN = 117;
const int MAXM = 100000;
const int INF = 0x3f3f3f3f;
struct Edge
{
int to,next,cap,flow,cost;
} edge[MAXM];
int head[MAXM],tol;
int pre[MAXM],dis[MAXM];
bool vis[MAXM];
//int N;//节点总个数,节点编号从0~N-1
int start, end;//源点和汇点
void init()
{
tol = 0;
memset(head,-1,sizeof(head));
}
void addedge(int u,int v,int cap,int cost)//左端点,右端点,容量,花费
{
edge[tol].to = v;
edge[tol].cap = cap;
edge[tol].cost = cost;
edge[tol].flow = 0;
edge[tol].next = head[u];
head[u] = tol++;
edge[tol].to = u;
edge[tol].cap = 0;
edge[tol].cost = -cost;
edge[tol].flow = 0;
edge[tol].next = head[v];
head[v] = tol++;
}
bool spfa(int s,int t)
{
queue<int> q;
for(int i = 0; i < MAXM; i++)
{
dis[i] = INF;
vis[i] = false;
pre[i] = -1;
}
dis[s] = 0;
vis[s] = true;
q.push(s);
while(!q.empty())
{
int u = q.front();
q.pop();
vis[u] = false;
for(int i = head[u]; i != -1; i = edge[i].next)
{
int v = edge[i].to;
if(edge[i].cap > edge[i].flow &&
dis[v] > dis[u] + edge[i].cost )
{
dis[v] = dis[u] + edge[i].cost;
pre[v] = i;
if(!vis[v])
{
vis[v] = true;
q.push(v);
}
}
}
}
if(pre[t] == -1)
{
return false;
}
else
return true;
}
//返回的是最大流, cost存的是最小费用
int minCostMaxflow(int s,int t,int &cost)
{
int flow = 0;
cost = 0;
while(spfa(s,t))
{
int Min = INF;
for(int i = pre[t]; i != -1; i = pre[edge[i^1].to])
{
if(Min > edge[i].cap - edge[i].flow)
Min = edge[i].cap - edge[i].flow;
}
for(int i = pre[t]; i != -1; i = pre[edge[i^1].to])
{
edge[i].flow += Min;
edge[i^1].flow -= Min;
cost += edge[i].cost * Min;
}
flow += Min;
}
return flow;
}
int sum = 0 ;
int shop[MAXN][MAXN], supply[MAXN][MAXN];
void build(int n, int m, int p)
{
sum = 0;
init();
start = 0;
end = n+m+1;
for(int i = 0; i < m; i++)//源点到供应商
{
addedge(start, i+1, supply[i][p], 0);
}
for (int i = 0; i < n; i++)//店主到汇点
{
addedge(i+1+m, end, shop[i][p], 0);//左端点,右端点,容量,花费
sum += shop[i][p];
}
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
int cost;
scanf("%d",&cost);
//供应商到店主
addedge(j+1, i+1+m, INF, cost);
}
}
}
int main()
{
int n, m, k;
while(~scanf("%d%d%d",&n,&m, &k))
{
//n:店主 m:供应商 k:物品种类
if(n==0 && m==0 && k==0)
{
break;
}
int flag = 0;
int ans = 0;
for(int i = 0; i < n; i++)
{
for(int j = 0; j < k; j++)
{
scanf("%d",&shop[i][j]);//店主需求的数量
}
}
for(int i = 0; i < m; i++)
{
for(int j = 0; j < k; j++)
{
scanf("%d",&supply[i][j]);//供应商能供应的数量
}
}
for(int i = 0; i < k; i++)
{
int flow, t_ans;
build(n, m, i);
if(!flag)
{
flow = minCostMaxflow(start, end,t_ans);
ans +=t_ans;
}
if(flow != sum)
flag = 1;
}
if(flag)
{
printf("-1\n");
}
else
{
printf("%d\n",ans);
}
}
return 0;
}
POJ 2516 Minimum Cost(最小费用最大流啊)
原文地址:http://blog.csdn.net/u012860063/article/details/45699749