题目链接: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