先宣告,來自網路,寫得也比較亂,如果有任何問題可以聯絡博主。
首先,我們來理解下網路流。
在乙個有向圖上選擇乙個源點,乙個匯點,每一條邊上都有乙個流量上限(以下稱為容量),即經過這條邊的流量不能超過這個上界,同時,除源點和匯點外,所有點的入流和出流都相等,而源點只有流出的流,匯點只有匯入的流。這樣的圖叫做網路流。
定義:源點:只出不進的點
匯點:只進不出的點
流量和容量:流量,表示該條邊流過的流量(額,,反正就那個意思,理解就行了,細節就不要糾結了啊);容量,即該條邊的流量上限
殘量:該條邊上還可以繼續擴大的流量範圍,即容量-已流過的流量
最大流:即再不超過容量範圍內,使得所有邊上的流量最大,這個流量就是最大流量
(上圖中,1為源點,6為匯點,最大流量為7)
求解思路:
首先,假如所有邊上的流量都沒有超過容量(不大於容量),那麼就把這一組流量,或者說,這個流,稱為乙個可行流。
乙個最簡單的例子就是,零流,即所有的流量都是0的流。
(1).我們就從這個零流開始考慮,假如有這麼一條路,這條路從源點開始一直一段一段的連到了匯點,並且,這條路上的每一段都滿足流量《容量,注意,是嚴格的
(2).那麼,我們一定能找到這條路上的每一段的(容量-流量)的值當中的最小值delta。我們把這條路上每一段的流量都加上這個delta,一定可以保證這個流依然是可行流,這是顯然的。
(3).這樣我們就得到了乙個更大的流,他的流量是之前的流量+delta,而這條路就叫做增廣路。我們不斷地從起點開始尋找增廣路,每次都對其進行增廣,直到源點和匯點不連通,也就是找不到增廣路為止。
(4).當找不到增廣路的時候,當前流量就是最大流。
如下圖:
我們知道,當我們在尋找增廣路的時候,在前面找出的不一定是最優解,如果我們在減去殘量網路中正向邊的同時將相對應的反向邊加上對應的值,我們就相當於可以反悔從這條邊流過。
比如說我們現在選擇從u流向v一些流量,但是我們後面發現,如果有另外的流量從p流向v,而原來u流過來的流量可以從u->q流走,這樣就可以增加總流量,其效果就相當於p->v->u->q,用圖表示就是:
圖中的藍色邊就是我們首次增廣時選擇的流量方案,而實際上如果是橘色邊的話情況會更優,那麼我們可以在v->u之間連一條邊容量為u->v減去的容量,那我們在增廣p->v->u->q的時候就相當於走了v->u這條"邊",而u->v的流量就與v->u的流量相抵消,就成了中間那幅圖的樣子了。
如果是v->u時的流量不能完全抵消u->v的,那就說明u還可以流一部分流量到v,再從v流出,這樣也是允許的。
雖然說我們已經想明白了為什麼要加反向邊,但反向邊如何具體實現呢?。
首先講一下鄰接矩陣的做法,對於g[u][v],如果我們要對其反向邊進行處理,直接修改g[v][u]即可。
但有時會出現u->v和v->u同時本來就有邊的情況,一種方法是加入乙個新點p,使u->v,而v->u變成v->p,p->u。
另一種方法就是使用鄰接表,我們把邊從0開始編號,每加入一條原圖中的邊u->v時,加入邊v->u流量設為0,那麼這時對於編號為i的邊u->v,我們就可以知道i^1就是其反向邊v->u。
雖然說我們已經知道了增廣路的實現,但是單純地這樣選擇可能會陷入不好的境地,比如說這個經典的例子:
我們一眼可以看出最大流是999(s->v->t)+999(s->u->t),但如果程式採取了不恰當的增廣策略:s->v->u->t
我們發現中間會加一條u->v的邊
而下一次增廣時:
若選擇了s->u->v->t
然後就變成
這是個非常低效的過程,並且當圖中的999變成更大的數時,這個劣勢還會更加明顯。
怎麼辦呢?
這時我們引入dinic演算法
為了解決我們上面遇到的低效方法,dinic演算法引入了乙個叫做分層圖的概念。具體就是對於每乙個點,我們根據從源點開始的bfs序列,為每乙個點分配乙個深度,然後我們進行若干遍dfs尋找增廣路,每一次由u推出v必須保證v的深度必須是u的深度+1。
如圖:
下面放**,結合**就不難理解:(洛谷模板題)
#include#define inf 2147483647using
namespace
std;
const
int n=1e5+7
;int
n,m,sta,ed,head[n],cur[n],cnte,dep[n],ans;
struct edge e[n<<1
];queue
q;inline
intread()
while( ch>='
0' && ch<='9'
)
return flag ? -x : x;
}inline
void add(int x,int y,int
z)inline
bool
bfs()
}return dep[ed]>0;}
int dfs(int x,int
flow)
}return
used;
}int
main()
while
( bfs() )
return printf("
%d\n
",ans),0
;}
網路流 學習筆記
略。update 我發現我的最大流一直是寫錯的!寫錯一年了!這一年居然沒有被卡真是奇蹟 void dedge int sta,int edn,lon w fst sta ecnt void edge int sta,int edn,lon w bool bfs return 0 lon dfs in...
網路流學習筆記
基本思路 實現 include include include include using namespace std const int maxn 100 const int maxm maxn maxn const int inf 0x3f3f3f3f int head maxn next ma...
網路流學習筆記(2)
最小費用最大流 在保證最大流的前提下,讓費用最小。我們有兩種思路 1.先保證流最大,再去找費用最小的。2.保證費用最小,去找最大流。通常情況下我們會選擇第二種。我們想一下最大流是怎麼做的,bfs分層圖然後dfs每次只找深度 1的去增廣。如果我們要保證最小費用呢?每次去找費用最小的增廣。我們可以spf...