最小費用最大流
阿新 • • 發佈:2017-07-25
dinic min man 多個 轉化 pan 多少 最短路 +=
一、問題描述
最小費用最大流: 在最大流有多組解時,給每條邊在附上一個單位費用的量,問在滿足最大流時的最小費用是多少?
二、算法描述
思想: 給出一個容量網絡,那他的最大流一定是一個定值(即使是有多個一樣的最大值)。所以我們從開始的可行流開始增廣時,最終的增廣量是一定的。所以為了滿足最小費用我們只需要每次找最小費用的增廣路即可,直到流量為最大值。這個問題僅僅是在求增廣路時先考慮費用最小的增廣路,其他思想和EK思想一樣。
我們學過SPFA求最短路算法(bellman-ford的隊列優化),所以我們將弧的費用看做是路徑長度,即可轉化為求最短路的問題了。只需要所走的最短路滿足兩個條件即可:1可增廣cap> flow,2路徑變短d[v]>d[u]+cost< u,v> 。
關於建圖的方式和Dinic,ISAP算法一樣,如有疑問可以去我們其他相關博客看看。
模板:
//最小費用最大流,求最大費用只需要取相反數,結果取相反數即可。 //點的總數為 N,點的編號 0~N-1 const int MAXN = 10000; const int MAXM = 100000; const int INF = 0x3f3f3f3f; struct Edge { int to,next,cap,flow,cost; }edge[MAXM]; int head[MAXN],tol; int pre[MAXN],dis[MAXN]; bool vis[MAXN]; int N;//節點總個數,節點編號從0~N-1 void init(int n) { N = n; 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 < N;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; }
最小費用最大流