图论 —— 网络流 —— 最大流 —— 压入与重标记算法
生活随笔
收集整理的這篇文章主要介紹了
图论 —— 网络流 —— 最大流 —— 压入与重标记算法
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
【概述】
壓入與重標記算法(Push-Relable Algorithms)又稱預留推進算法,是 GoldBerg 與 Tarjan 共同發現的,時間復雜度為 O(V*V*E)
該算法與 EK 、Dinic 等增廣路算法一樣是用于求最大流的,不同于增廣路算法檢查整個殘留網絡來找出增廣路徑,該算法每次僅對一個頂點進行操作,并且檢查殘量網絡中該點相鄰的點。
【算法原理】
首先引入新名詞的定義:
- 余流:對于一個頂點,依舊存儲在該點中,尚未排除的流量,記作:excess(u)= f(V,v)>=0
- 活性點:對于一個不屬于源點、匯點的任意點 v,若其容量有限且其余流大于 0,那么稱該點為一活性點,且該點流量溢出
- 點的高度:每個點 i 被賦予了一個高度 height(i),余流只能從高向下壓入比他低的頂點
- 合法標記:對于圖中的任意一條邊 (u,v),若滿足 height(u)<=height(v)+1,那么具有一個合法標記,而僅當?height(u)=height(v)+1?時,才將流從 u 壓入 v
假設每個頂點 u 存在無限大容量的水庫,可以用來儲存任意多的水,儲存在該頂點的流量即為該點的余流
在開始時,令除 S、T 兩點外的點的高度為?height(S)=|V|,height(T)=0 固定不變,其他點的高度 height(i) 初始化為 0,隨著算法進行不斷進行調整
令所有從源點 S?出來的邊,達到飽和狀態,成為飽和邊,然后盡量使這個余流達到匯點 T,若是有一部分無法到達 T,那么將剩下的余流返回源點?S,當任意一點 u 的余流 excess(u)=0 時,算法停止,返回最大流
每個點與其關聯的的點處于同一高度,當需要壓入點 u 的流量時(Push(u) 操作),重標記點 u 的高度 height(u)(relabel(u) 操作),使得點 u 的余流流向高度小于他的點 v,直到存在一點的余流為 0
【實現】
int cap[N][N]; //容量網絡 int flow[N][N]; //流量網絡 int height[N]; //高度標記 int excess[N]; //余流 void push(int start, int end) {int newflow = min(excess[start], cap[start][end] - flow[start][end]);//改變當前流量flow[start][end] += newflow;flow[end][start] = -flow[start][end];//改變余流excess[start] -= newflow;excess[end] += newflow; }bool reLabel(int S, int T, int index) { //重標記int minn = INF; //最小的高度for (int i = S; i <= T; i++)if (cap[index][i] - flow[index][i] > 0)minn = min(minn, height[i]);if (minn == INF)return false;height[index] = minn + 1; //滿足height(u)=height(v)+1,標記下放for (int i = S; i <= T; i++) {if (excess[index] == 0) //余流為0,標記下放結束,返回truereturn true;if (height[i] == minn &&cap[index][i] > flow[index][i]) //處于同一高度,壓入流量push(index, i);}return true; }void pushReLabel(int S, int T) {//預處理余流for (int i = S; i <= T; i++) {if (cap[S][i] > 0) {int newflow = cap[S][i];flow[S][i] += newflow;flow[i][S] = -flow[S][i];excess[S] -= newflow;excess[i] += newflow;}}bool flag = true;while (true) {if (!flag)break;flag = false;for (int i = S; i <= T - 1; i++) {if (excess[i] > 0) { //當余流大于0時,繼續重標記if (flag || reLabel(S, T, i))flag = true;}}} }int main() {int n, m;while (scanf("%d%d", &n, &m) != EOF) {memset(cap, 0, sizeof(cap));memset(flow, 0, sizeof(flow));memset(height, 0, sizeof(height));memset(excess, 0, sizeof(excess));int S = 1, T = n;height[S] = n;height[T] = 0;for (int i = 1; i <= m; ++i) {int x, y, w;scanf("%d%d%d", &x, &y, &w);cap[x][y] = w;}pushReLabel(S, T);int res = excess[T]; //匯點的余流即最大流printf("%d\n", res);}return 0; }?
新人創作打卡挑戰賽發博客就能抽獎!定制產品紅包拿不停!總結
以上是生活随笔為你收集整理的图论 —— 网络流 —— 最大流 —— 压入与重标记算法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 图论 —— 生成树 —— 生成树计数 —
- 下一篇: 理论基础 —— 查找 —— 平衡二叉树