[模板]最小费用最大流
最小费用最大流
(以下来自百度百科)
最小费用最大流问题是经济学和管理学中的一类典型问题。在一个网络中每段路径都有“容量”和“费用”两个限制的条件下,此类问题的研究试图寻找出:流量从A到B,如何选择路径、分配经过路径的流量,可以在流量最大的前提下,达到所用的费用最小的要求。如n辆卡车要运送物品,从A地到B地。由于每条路段都有不同的路费要缴纳,每条路能容纳的车的数量有限制,最小费用最大流问题指如何分配卡车的出发路径可以达到费用最低,物品又能全部送到。
一个网络流图中最大流的流量max_flow是唯一的,但是当每一条都有一个费用时,达到max_flow的费用不一定是唯一的,最小费用最大流就是当流量最大时,费用最小为多少。
即每条边都设置一个费用cost,表示单位流量流经该边时会导致花费cost。
算法实现思路:
采用贪心的思想,每次找到一条从源点到达汇点的路径,增加流量,且该条路径满足使得增加的流量的花费最小,直到无法找到一条从源点到达汇点的路径,算法结束。
由于最大流量有限,每执行一次循环流量都会增加,因此该算法肯定会结束,且同时流量也必定会达到网络的最大流量;同时由于每次都是增加的最小的花费,即当前的最小花费是所有到达当前流量flow时的花费最小值,因此最后的总花费最小。
//形象感知
求解步骤
(1)找到一条从源点到达汇点的“距离最短”的路径,“距离”使用该路径上的边的单位费用之和来衡量。
(2)然后找出这条路径上的边的容量的最小值f,则当前最大流max_flow扩充f,同时当前最小费用min_cost扩充f*min_dist(s,t)
(3)将这条路径上的每条正向边的容量都减少f,每条反向边的容量都增加f。
(4)重复(1)--(3)直到无法找到从源点到达汇点的路径。
我们每次要更新的时候就可以在费用网络上跑最短路。因为有负权的问题,我们可以用spfa跑。
#include <cstdio> #include <algorithm> #include <queue> #define gc getchar() #define oo 99999999; using namespace std; const int N = 5010; int n, m, S, T, now; int head[N], dis[N], pre[N]; bool vis[N]; struct Node{int u, v, cost, flow, nxt;} G[(N * 10) << 1]; queue <int> Q; inline int read(){ int x = 0; char c = gc; while(c < '0' || c > '9') c = gc; while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = gc; return x; } inline void add(int u, int v, int cost, int flow){ G[now].u = u; G[now].v = v; G[now].cost = cost; G[now].flow = flow; G[now].nxt = head[u]; head[u] = now ++; } inline bool spfa(int start, int endd){ for(int i = 1; i <= n; i ++) vis[i] = 0, dis[i] = oo; dis[start] = 0; Q.push(start); while(!Q.empty()){ int topp = Q.front(); Q.pop(); vis[topp] = 0; for(int i = head[topp]; ~ i; i = G[i].nxt){ int v = G[i].v; if(dis[v] > dis[topp] + G[i].cost && G[i].flow > 0){ dis[v] = dis[topp] + G[i].cost; pre[v] = i; if(!vis[v]) vis[v] = 1, Q.push(v); } } } return dis[endd] != oo; } inline void Mfmc(int & F, int & C){ while(spfa(S, T)){ int endd = T, Now; int min_f = oo; while(1) { Now = pre[endd]; min_f = min(min_f, G[Now].flow); if(G[Now].u == S) break; endd = G[Now].u; } F += min_f; C += dis[T] * min_f; endd = T; while(1){ Now = pre[endd]; G[Now].flow -= min_f; G[Now ^ 1].flow += min_f; if(G[Now].u == S) break; endd = G[Now].u; } } } int main() { n = read(); m = read(); S = read(); T = read(); for(int i = 1; i <= n; i ++) head[i] = -1; for(int i = 1; i <= m; i ++) { int u = read(), v = read(), flow = read(), cost = read(); add(u, v, cost, flow); add(v, u, - cost, 0); } int Max_flow(0), Min_cost(0); Mfmc(Max_flow, Min_cost); printf("%d %d", Max_flow, Min_cost); return 0; } /* 4 5 4 3 4 2 30 2 4 3 20 3 2 3 20 1 2 1 30 9 1 3 40 5 */
比较快,相对难写
#include <iostream> #include <cstdio> #include <algorithm> #include <queue> using namespace std; const int N = 1e4 + 10;//dian const int NN = 1e5 + 10;//bian const int INF = 9999999; int head[N], dis[N], belong[N]; bool vis[N]; int n, m, S, T, ans_flow, ans_cost, now = 1; struct Node { int u, v, flow, cost, nxt; } E[NN]; queue <int> Q; inline int read() { int x = 0, f = 1; char c = getchar(); while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); } while (c >= '0' && c <= '9') x = x * 10 + c -'0', c = getchar(); return x * f; } inline void add(int u, int v, int flow, int cost) { E[now].u = u; E[now].v = v; E[now].flow = flow; E[now].cost = cost; E[now].nxt = head[u]; head[u] = now ++; } int AP(int start, int minn) { if (start == S) return minn; int ret = AP(E[belong[start]].u, min(minn, E[belong[start]].flow)); if (!E[belong[start] ^ 1].cost) { now = belong[start] ^ 1; add(start, E[belong[start]].u, 0, -E[belong[start]].cost); } E[belong[start]].flow -= ret; E[belong[start] ^ 1].flow += ret; return ret; } inline void MCMF() { while(1) { for (int i = 1; i <= n; i ++) dis[i] = INF, vis[i] = 0; dis[S] = 0; Q.push(S); while (!Q.empty()) { int topp = Q.front(); Q.pop(); vis[topp] = 0; for (int i = head[topp]; ~ i; i = E[i].nxt) { if (dis[E[i].v] > dis[topp] + E[i].cost && E[i].flow) { dis[E[i].v] = dis[topp] + E[i].cost; belong[E[i].v] = i; if (!vis[E[i].v]) { vis[E[i].v] = 1; Q.push(E[i].v); } } } } if (dis[T] == INF) break; int now_flow = AP(T, INF); ans_flow += now_flow; ans_cost += now_flow * dis[T]; } } int main()
{ n = read(); m = read(); S = read(); T = read(); for (int i = 1; i <= n; i ++) head[i] = -1; for (int i = 1; i <= m; i ++) { int au = read(); int av = read(); int aflow = read(); int acost = read(); ++ now; add(au, av, aflow, acost); } MCMF(); printf("%d %d", ans_flow, ans_cost); return 0; }