網路流初步詳解中大致談了一下最大流的一些演算法,其中dinic是非常重要的,補一句:最大流 == 最小割。
本文包括:
1.費用流的概念及基本性質
2.edmonds-karp增廣路演算法求費用流
3.一些關於費用流的技巧
4.關於費用流的刷題指南
//假設您已經理解了dinic演算法和ek演算法二者之一。
對於我們原來的網路流,現在給你乙個網路,每條邊除了有流量(容量)的限制外,還有乙個單位費用,經過這條邊,我們不僅要符合可行流的條件,還要付出乙個費用 = 單位費用和該邊流量之積。
而對於費用流,現在主要可分為「最小費用最大流」和「最大費用最大流」兩種基本題型。(至於最小流一般會出現在有上下界的網路流中,這個會在網路流初步詳解3中講解)
最重要的,上述兩種基本題型模板基本相同,並且是以最大流為前提。
再次重複:您需要理解了dinic演算法和ek演算法二者之一,這樣你可以在5分鐘內學會費用流模板。
我們在這裡考慮,為什麼不能在dinic演算法的基礎上求出費用流。
這裡簡單談下,dinic演算法是乙個基於殘量網路上不斷找出増廣路的演算法,我們在找増廣路時,只是考慮了流量和分層圖的深度問題,而我們加上單位費用限制後,這種只要可以増廣就馬上増廣的演算法就難以變通。
這是我們不妨考慮效率較低,但每次bfs只隨機找到一條増廣路的edmonds-karp增廣路演算法。我們很容易發現,我們可以限制這個「隨機」増廣路,從而讓它滿足費用最大或最小的條件。具體我們將採用乙個鮮為人知的被卡死spfa來實現。
先說一下,為了滿足我們最大流的「斜對稱」原則,及我們可以反悔,以求出最大流,反邊的單位費用稍作處理,賦值為 -w
void add_edge(int x, int y, int z, int c)
然後我們來講解具體的最短路上實現増廣路操作。(這裡給出最小費用最大流)
這裡給出2個**,前者是正確的,而後者可能會出現tle和wa的錯誤,請讀者仔細思考。
ac:
bool spfa() }}
if ( dis[t] == 0x3f3f3f3f ) return false; // 匯點不可達,已求出最大流
return true;
}void update()
maxflow += flow[ t ] ;
ans += dis[ t ]*flow[ t ] ;//這裡多解釋一下,由於只掃出了一條増廣路,不可能存在有像dinic一樣的流量分叉,加之流量守恆定律,所以這條増廣路上增加的可行流量在每條邊上都相等。
}
多種方案可滿足最大流時tle和wa**片段
for( register int i = head[ x ] ; i ; i = nex[ i ] )
}}//省略了部分相同**
void update()
maxflow += flow[ t ] ;
ans += dis[ t ] ;//這裡的dis已經是實際消費。
}
在感性理解上,2個**片段給讀者的感覺是:好像都一樣的呀?而且後者彷彿正確性格更顯然啊。在我第一次看的時候,我百思不得其解。為了具體,給你乙個樣例,請讀者不要跳過此節:
假設我現在有 8 的流量要流出,有且僅有兩條可行邊,都可以滿流到達匯點,分別為
a邊: 流量為 10 , 單位費用為 2 。 滿流全費 20
b邊: 流量為 2 , 單位費用為 4 。 滿流全費 8
最優策略(ac**):全流a邊 20費 。
感性策略(wa**):b 滿流全費小於 a , b費 8 , a費16 , 總費 26 。
感性策略的方法只滿足了區域性最優解(雖然可以保證最大流),而不能維護整體最優解。
這種情況只有在有多種方案可滿足最大流時會中等機率(看資料)tle或者wa。
完整ac**:(改自李煜東的模板,這個板子親測常數較小,碼風清奇)
#includeusing namespace std;
const int maxn = 5010, maxm = 100010 , oo = ( 1 << 30 ) ;
int to[ maxm*2 ], w[ maxm*2 ], cost[ maxm*2 ], nex[ maxm*2 ], head[ maxn ];
int dis[ maxn ] , flow[ maxn ] , pre[ maxn ] ;
int n , m , s , t , maxflow , ans, tot = 1 ;
bool v[ maxn ] ;
inline int read()
while(g>='0'&&g<='9')
return s*w;
}//(快讀很醜,但費用流**很好記)
void add(int x, int y, int z, int c)
bool spfa() }}
if ( dis[t] == 0x3f3f3f3f ) return false; // 匯點不可達,已求出最大流
return true;
}void update()
maxflow += flow[ t ] ;
ans += dis[ t ]*flow[ t ] ;
}int main()
while (spfa()) update(); // 計算最小費用最大流
cout<< maxflow <<" "《例題來自洛谷【模板】最小費用最大流。
3.一些關於費用流的技巧
無論是最大流還是費用流中,讀題,抽象,建圖,這才是最重要的,板子幾乎不會變。
可以在二分圖的公升級版--帶權二分圖上愉快地跑網路流。
我們在很多時候都需要拆點操作,以達到限流或限費的目的。
我們在題目中會遇到很多要建立一些0費的邊,以此達到連線和其他的目的。
在【網路流初步詳解3】中我還將講解一些在有上下界的費用流的一些技巧。(暫時鴿了,因為本人太菜,可能不久後就會面臨退役,所以會先鞏固noip)
4.關於費用流的刷題指南
馬上上傳
網路流初步
問題 最大流問題 假設 把一些物品從結點s 源點 運送到t 匯點 可以從其他結點中轉。1.容量 對於一條邊 u,v 它的物品上限成為容量,記為c u,v 2.流量 實際運送的物品成為流量,記為f u,v 目標 最大化從s點流出的淨流量,即最大化 容量c與流量f滿足3個性質 1.容量限制 對g中的每條...
網路流初步 sap演算法
什麼是網路流?請看下圖 這是乙個有向圖,每一條邊都對應著兩個數值 前面的稱為流量,用f u,v 表示,後面的稱為容量,用c u,v 表示,網路中有兩個特殊的點,源點s和匯點t。一 容量限制,對於所有原圖中的變,均有f u,v c u v 二 反對稱性,為了方便計算,我們定f u,v 和f v u 中...
2021 網路流初步
首先是一些概念,容量,流量,飽和弧,非飽和弧,零弧,非零弧,增廣路,殘量,殘量網路 這個方法的時間複雜度比較差 為 一直bfs找增廣路,直到找不到演算法結束,每次找到後,修改正向邊和反向邊的邊權即可 includeusing namespace std int n,m,s,t const int i...