一篇巨佬的網路流建模
網路最大流問題就是給你乙個有向圖,告訴你乙個源點與乙個匯點,並給每一條邊乙個最大流量,需要你求出從源點最多能夠發出多少單位流量到匯點(哎呀我也說不清,就是給你一些或大或小的管道(每個管道都有最大秒流量),一些中轉站,一座供水塔以inf單位每秒的速度供水,問你家每秒最多得到多少單位水(中轉站、供水塔、你家由管道連通))
很顯然看起來我們可以從源點跑dfs,只要到下一節點的邊的邊權》0就跑到下一節點,一路跑過去,直到匯點,然後答案加上這一路上最小的管道流量,這一條路徑上所有管道減去這個流量,然後就沒了。
但是這樣子是有問題的。(藍模板怎麼可能這麼簡單)
舉個栗子:(將dfs路徑用紅色表示)
然後你會發現這樣的答案是2,然而正確的答案是4(s-2-t,s-3-t)
(不要說你的存邊是2-t比2-3優先,調個位置就卡掉了)
為什麼會這樣?
因為上圖中第一條dfs路徑把原本應是第二條路徑的一條邊給「占用」了。
計算機可不是人,它無法判斷到底該怎麼跑dfs,所以這時候就需要我們人為地給計算機乙個「反悔」的機會。
重點:怎麼讓計算機「反悔」?
給每條邊建邊權為0的反向邊,當每次跑到匯點時,在回溯給dfs路徑上的邊權減去最小邊權的時候還要給反向邊加上最小邊權。
先看效果:
然後答案就神奇地變成4了!
為什麼?
用整體的思想來看:如果我正著經過一條邊,再反著經過,是不是相當於沒經過?好吧,我承認這不是很好理解
這一種「抵消」的思想應用十分廣泛,比如洛谷p1792 [國家集訓隊]種樹,就是一種利用類似「抵消」的方法來實現的可反悔的貪心。
沒理解也沒關係,反正就是要反向建邊,題做多了就理解了qaq
使用了這種「抵消」思想的dfs,大概就是所謂的ek演算法了。(即不停的尋找增廣路然後操作)
然後再介紹一種優化演算法:dinic演算法(本質上其實差不多,只不過是一次尋找多條增廣路並更新圖)
ps:增廣路即能夠使答案增加的dfs路徑
大概步驟就是:
1.bfs——給之後尋找增廣路的dfs提供乙個bfs序作為擴充套件增廣路的依據,同時判斷是否還存在增廣路(如果遍歷不到匯點,就退出輸出答案)。
2.dfs——尋找增廣路(注意這裡一次尋找了多條)並更新答案。
3.重複1
dinic的**實現:(貼上我洛谷p3376 【模板】網路最大流的**)
#include#include#include#define maxn 20010
#define maxm 200010
#define inf 0x3f3f3f3f
using namespace std;
int bg[maxn],nt[maxm],to[maxm],w[maxm],e=1;
int dep[maxn],q[maxn],n,m,s,t,ans;
void insert(int x,int y,int z)
void bfs()
}}int dfs(int x,int s)
}return res;
}int main()
while (1)
printf("%d\n",ans);
return 0;
}
洛谷p2764 最小路徑覆蓋問題
我的題解qwq
洛谷p3355 騎士共存問題
暫時我沒寫題解qaq
附:當前弧優化
聽名字似乎是乙個很高階的東西,但其實很簡單,就幾句話。。。
我們維護乙個now陣列,在每次dfs前把鏈式前向星的bg陣列(或者是head)拷貝乙份到now上,然後在dfs列舉邊找下乙個節點時迴圈列舉邊的編號不再從bg[x]開始了,而從now[x]開始。而now[x]不斷地更新,即i迴圈到哪,now[x]都更新為i。(具體實現還是看**吧,我的語言表達能力一向不強)
這樣子可以大大提公升程式效率。
**:
#include#include#include#define maxn 20010
#define maxm 200010
#define inf 0x3f3f3f3f
using namespace std;
int bg[maxn],nt[maxm],to[maxm],w[maxm],e=1;
int dep[maxn],q[maxn],n,m,s,t,ans,now[maxn];
void insert(int x,int y,int z)
void bfs()
}}int dfs(int x,int s)
now[x]=i;
}return res;
}int main()
while (1)
printf("%d\n",ans);
return 0;
}
實測效率截圖o_o!:
優化之前:
之後:
至於這個優化的正確性,蒟蒻引用一句很6的話(畢竟我描述不出來)——
「對於一次bfs而言,它確定的層次圖中每條邊若已經被走完了,那麼它就不可能再帶來增廣,下一次就直接從這條最後沒走完的邊走就可以了。」
網路流 最大流 dinic 當前弧優化 模板
用法 在原有向圖的基礎上,增加源點s和匯點t,並將s與左子集建邊,t與右子集建邊 邊權都設為1,則就是求二分圖最大匹配 右子集與t的邊權大於1,則就是求二分圖最大多重匹配 模板 const int n 210 struct edge edge n n 邊數 int head n cnt void a...
模板 網路最大流 最大流
給出乙個網路圖,以及其源點和匯點,求出其網路最大流。in put role presentation inp utin put4 5 4 3 4 2 30 4 3 20 2 3 20 2 1 30 1 3 40ou tput role presentation out puto utpu t50最大...
模板 網路最大流 最大流
給出乙個網路圖,以及其源點和匯點,求出其網路最大流。in put role presentation inp utin put4 5 4 3 4 2 30 4 3 20 2 3 20 2 1 30 1 3 40ou tput role presentation out puto utpu t50最大...