POJ2516

题目链接:http://poj.org/problem?id=2516

解题思路:

  最小费用最大流,这个没什么疑问。但此题小难点在于读题,大难点在于建图。

  首先,供应量小于需求量的时候直接输出“-1”。

  供大于或等于求的情况,一开始我将每个供应商和每个购买人都拆成K个点,将所有供应商的点和超级源点相连,流量限制为库存量,费用为0;将所有购买人的点和超级汇点相连,流量限制为购买量,费用为0;而购买方和供应方之间的连线的流量限制则为inf,费用如题目中给出的。但是这种建图方式一直T......一度绝望到以为我的模板有问题,修修补补了半天,还是T......上网查了题解,发现大家的建图方式跟我不一样:大家都是把根据K种商品,建K个图逐一求最小费用最大流,答案就是K个图的最小费用之和。稍微改了一下,AC.......醉........至于为什么........我也不太懂,容我明天去问问师兄。

AC代码:

  1 #include <cstdio>
  2 #include <vector>
  3 #include <queue>
  4 #include <cstring>
  5 using namespace std;
  6
  7 const int MAXN = 5000;
  8 const int MAXM = 100000;
  9 const int INF = 0x3f3f3f3f;
 10 struct rec {
 11     int from, to, cost, cap;
 12 }r[55][2550];
 13 struct Edge {
 14     int to, next, cap, flow, cost;
 15 }edge[MAXM];
 16 int head[MAXN], tol;
 17 int pre[MAXN], dis[MAXN];
 18 bool vis[MAXN];
 19 int N;
 20 void init(int n) {
 21     N = n;
 22     tol = 0;
 23     memset(head, -1, sizeof(head));
 24 }
 25 void addedge(int u, int v, int cap, int cost) {
 26     edge[tol].to = v;
 27     edge[tol].cap = cap;
 28     edge[tol].cost = cost;
 29     edge[tol].flow = 0;
 30     edge[tol].next = head[u];
 31     head[u] = tol++;
 32     edge[tol].to = u;
 33     edge[tol].cap = 0;
 34     edge[tol].cost = -cost;
 35     edge[tol].flow = 0;
 36     edge[tol].next = head[v];
 37     head[v] = tol++;
 38 }
 39 bool spfa(int s, int t) {
 40     queue<int>q;
 41     for (int i = 0; i < N; i++) {
 42         dis[i] = INF;
 43         vis[i] = false;
 44         pre[i] = -1;
 45     }
 46     dis[s] = 0;
 47     vis[s] = true;
 48     q.push(s);
 49     while (!q.empty()) {
 50         int u = q.front();
 51         q.pop();
 52         vis[u] = false;
 53         for (int i = head[u]; i != -1; i = edge[i].next) {
 54             int v = edge[i].to;
 55             if (edge[i].cap > edge[i].flow && dis[v] > dis[u] + edge[i].cost){
 56                 dis[v] = dis[u] + edge[i].cost;
 57                 pre[v] = i;
 58                 if (!vis[v]){
 59                     vis[v] = true;
 60                     q.push(v);
 61                 }
 62             }
 63         }
 64     }
 65     if (pre[t] == -1)    return false;
 66     else    return true;
 67 }
 68 int minCostMaxflow(int s, int t, int &cost){
 69     int flow = 0;
 70     cost = 0;
 71     while (spfa(s, t)) {
 72         int Min = INF;
 73         for (int i = pre[t]; i != -1; i = pre[edge[i ^ 1].to]) {
 74             if (Min > edge[i].cap - edge[i].flow)
 75                 Min = edge[i].cap - edge[i].flow;
 76         }
 77         for (int i = pre[t]; i != -1; i = pre[edge[i ^ 1].to]) {
 78             edge[i].flow += Min;
 79             edge[i ^ 1].flow -= Min;
 80             cost += edge[i].cost * Min;
 81         }
 82         flow += Min;
 83     }
 84     return flow;
 85 }
 86 int sup[55][55], buy[55][55];
 87 int main() {
 88     int N, M, K;
 89     int need[53], have[53];
 90     while (scanf("%d%d%d", &N, &M, &K) == 3 && (N || M || K)) {
 91         memset(need, 0, sizeof(need));
 92         memset(have, 0, sizeof(have));
 93         int c;
 94         for (int i = 1; i <= N; i++) {
 95             for (int j = 1; j <= K; j++) {
 96                 scanf("%d", &c);
 97                 need[j] += c;
 98                 buy[j][i] = c;
 99             }
100         }
101         for (int i = 1; i <= M; i++) {
102             for (int j = 1; j <= K; j++) {
103                 scanf("%d", &c);
104                 have[j] += c;
105                 sup[j][i] = c;
106             }
107         }
108         bool yes = true;
109         for (int j = 1; j <= K; j++) {
110             if (have[j]<need[j]) yes = false;
111         }
112
113         int ans = 0;
114         for (int k = 1; k <= K; k++) {
115             if (yes)
116                 init(N + M + 2);
117             for (int i = 1; i <= N; i++) {
118                 for (int j = 1; j <= M; j++) {
119                     scanf("%d", &c);
120                     if (yes)
121                         addedge(j, M + i, INF, c);
122                 }
123             }
124             if (yes) {
125                 for (int i = 1; i <= M; i++)
126                     addedge(0, i, sup[k][i], 0);
127                 for (int i = 1; i <= N; i++)
128                     addedge(M + i, N + M + 1, buy[k][i], 0);
129                 int cost;
130                 minCostMaxflow(0, N + M + 1, cost);
131                 ans += cost;
132             }
133         }
134         if (!yes)
135             printf("-1\n");
136         else
137             printf("%d\n", ans);
138     }
139     return 0;
140 }
时间: 2024-08-08 09:31:37

POJ2516的相关文章

【POJ2516】Minimum Cost

[POJ2516]Minimum Cost 题意:有N个收购商.M个供应商.K种物品.对于每种物品,每个供应商的供应量和每个收购商的需求量已知.每个供应商与每个收购商之间运送该物品的运费已知.求满足收购商要求的前提下的最小运费.(n,M,K<=50,每种物品供求量<=3,单位运费<=100) 题解:怎么看怎么是最小费用流,但是刚学的KM算法,还是要用一下的~ 由于各种物品间没有影响,所以可以将k种物品拆开:由于供求量≤3,所以可以将供应商和收购商都拆开,然后跑KM算法. #include

最小费用最大流粗解 poj2516

最小费用最大流,一般解法如下: 在流量基础上,每条边还有权费用,即单位流量下的所需费用.在最大流量下,求最小费用.解法:在最大流算法基础上,每次按可行流增广改为每次用spfa按最小费用(用单位费用)增广,每次按每条边一单位费用求到达终点的最小费用(最短路),那么每次找到"最短路"(只是一条路,不是多条(dinic每次可以增广多条)),之后按这条路最大 可能流量增广(取这条路上残量最小的),直到无法增广为止.(实现细节点代码备注). 该题题意:m个供应地向n个商店供应k种物品,对于每种物

POJ-2516(最小费用最大流+MCMF算法)

Minimum Cost POJ-2516 题意就是有n个商家,有m个供货商,然后有k种商品,题目求的是满足商家的最小花费供货方式. 对于每个种类的商品k,建立一个超级源点和一个超级汇点.每个商家和源点连线,容量为需要的商品数,每个供货商和汇点连线,容量为可以提供的商品数. 然后对于商家和供货商之间的连线就是,容量为INF,而费用就是题目提供的费用信息. #include<iostream> #include<cstdio> #include<algorithm> #i

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

一开始我把每个店主都拆成k个点,然后建图..然后TLE.. 看题解= =哦,愚钝了,k个商品是独立的,可以分别跑k次最小费用最大流,结果就是k次总和.. 1 #include<cstdio> 2 #include<cstring> 3 #include<queue> 4 #include<algorithm> 5 using namespace std; 6 #define INF (1<<30) 7 #define MAXN 111 8 #de

多源多汇费用流——poj2516

网络流的题好难..感觉有点遭不住了 这题用矩阵存图,然后把k个物品,每个物品都求一次费用流 /* 多源多汇的费用流 其实是k个费用流 */ #include<bits/stdc++.h> using namespace std; #define inf 0x3f3f3f3f #define maxn 205 struct Edge{int to,nxt,w,c;}e[maxn<<2]; int head[maxn],tot,n,m,s,t; void init(){} void a

网络流强化-POJ2516

k种货物分开求解最小费用最大流,主要减少了寻找最短路的时间. #include<queue> #include<cstdio> #include<cstring> using namespace std; #define maxe 256000 //pay #define maxv 5120 //pay #define maxn 55 //pay #define sc scanf #define pt printf #define rep(i,a,b) for(int

acm常见算法及例题

转自:http://blog.csdn.net/hengjie2009/article/details/7540135 acm常见算法及例题 初期:一.基本算法:     (1)枚举. (poj1753,poj2965)     (2)贪心(poj1328,poj2109,poj2586)     (3)递归和分治法.     (4)递推.     (5)构造法.(poj3295)     (6)模拟法.(poj1068,poj2632,poj1573,poj2993,poj2996)二.图算法

ACM算法总结及刷题参考

参考:http://bbs.byr.cn/#!article/ACM_ICPC/11777 OJ上的一些水题(可用来练手和增加自信)(poj3299,poj2159,poj2739,poj1083,poj2262,poj1503,poj3006,poj2255,poj3094) 初期: 一.基本算法: (1)枚举. (poj1753,poj2965)    (2)贪心(poj1328,poj2109,poj2586)    (3)递归和分治法.     (4)递推.     (5)构造法.(po

CodeForces 498C Array and Operations(最大流)

题目是给一些数和<数对>的下标,然后进行操作:对某个<数对>中的两个数同时除以一个都能被它们整除且不等于1的数,要求的就是最多能进行多少次操作. 除数一定是素数,就是要决定某素数要除哪些<数对>使除的次数最多, ik + jk is an odd number 可以想到这个是个二分图,数最多100个,然后就用最大流做了. 有了POJ2516的经验之后,马上想到,素数是独立的,进行若干次最大流而不是拆若干点跑最大流(10^9大概最多拆30个点吧).. 然后我还是没AC,因