1. 程式人生 > >題解 洛谷 P3376 【【模板】網絡最大流】

題解 洛谷 P3376 【【模板】網絡最大流】

line 效率 tro 什麽 struct while utc 有一個 putc

本人很弱,只會Dinic、EK與Ford-Fulkerson...(正在學習ISAP...)

這裏講Dinic...

Dinic:與Ford-Fulkerson和的思路相似(話說好像最大流求解都差不多吧),也是使用深搜尋找增廣路(至於增廣路是什麽,只要在學最大流而不是借鑒他人代碼的應該都知道吧)。

但是(劃重點),Dinic有一個十分不一樣的地方(Dinic:我們不一樣,不一樣!),就是還用了**BFS**(是為了湊齊深搜廣搜召喚神龍)!

BFS有什麽用呢,除了使時間復雜度更上一層樓之外,還有什麽用呢?

這就是Dinic的神奇之處了,BFS反而使時間復雜度降低,與EK看似肩並肩(EK:O(nm^2) Dinic:O(n^2m))。看上去是肩並肩了,實則在題目上,Dinic基本都比EK優秀,特別是二分圖。

扯遠了,繼續講Dinic的BFS的用處。

BFS是為了劃分等級周朝的分封制!),使得在找增廣路時跳過一些對這條增廣路沒用的點,使DFS效率大大提高。

另外,代碼還可以加上當前弧優化與多路增廣使其更快。

多路增廣,設置一個變量used,記錄這條邊的流量,就不用搜到就退了,最後滿了再退出。

當前弧優化:設置一個數組,在BFS預處理中將它賦值head[i],就相當於鄰接表裏的head,但是(劃重點)它的值是隨著增廣的時候所變小的,然後下次增廣時就可以跳過已經用過的邊。

獻上我醜陋的代碼:

#include<cstdio>
#define INF 0x3f3f3f3f
#define
maxn 3000001 inline int read(){//快讀 int r=0,f=1; char c=getchar(); while(c<0||c>9){ if(c==-)f=-1; c=getchar(); } while(c>=0&&c<=9){ r=r*10+c-0; c=getchar(); } return r*f; } void write(int x)//快速輸出 { if
(x<0) putchar(-),x=-x; if(x>9) write(x/10); putchar(x%10+0); } struct edge{ int v,c,nxt; }e[2*maxn]; //struct max_Fow{//本來寫了結構體的 int S,T,N,head[maxn],q[maxn],cur[maxn],level[maxn],tot=0,hd,tl,v; inline void init(int s,int t,int n){//為結構體而寫 S=s; T=t; N=n+1; for(register int i=1;i<N;i++)//想想為什麽不直接為0 head[i]=-1; } inline void add_edge(int u,int v,int c){ e[tot]=(edge){v,c,head[u]};//為什麽從0開始? head[u]=tot++; } inline void add(int u,int v,int c){ add_edge(u,v,c); add_edge(v,u,0);//反向邊 } inline bool BFS(){ for(register int i=1;i<N;i++){ cur[i]=head[i];//當前弧優化初始化 level[i]=0;//等級初始化 } q[1]=S; level[S]=1; hd=0;tl=1; while(hd^tl){//廣搜 hd++; for(register int i=head[q[hd]];i!=-1;i=e[i].nxt){ if(e[i].c&&!level[e[i].v]){ tl++; level[e[i].v]=level[q[hd]]+1; q[tl]=e[i].v; if(e[i].v==T)return true;//搜到就退 } } } return false;//否則無法拓展到匯點 } inline int min(int a,int b){//手寫min if(a<b)return a; return b; } int DFS(int f,int u){ if(u==T)return f; int d=0,used=0;//多路增廣 for(int &i=cur[u];i!=-1;i=e[i].nxt){//當前弧優化 if(e[i].c&&level[u]==level[e[i].v]-1){ if((d=DFS(min(f-used,e[i].c),e[i].v))){ e[i].c-=d; e[i^1].c+=d;//為什麽可以直接這樣? used+=d;//多路增廣 } } } if(!used)level[u]=0; return used; } inline int Dinic(){//求解 int max_flow=0; while(BFS()){ int d=0; while((d=DFS(INF,S))) max_flow+=d; } return max_flow; } //}Flow; int main(){ int n=read(),m=read(),s=read(),t=read(),i; /*Flow.*/init(s,t,n); for(i=1;i<=m;i++){ int a=read(),b=read(),v=read(); /*Flow.*/add(a,b,v); } int ans=/*Flow.*/Dinic(); write(ans); return 0; }

Q:為什麽head[]初始值為-1更好?

A:因為開始值就會為0,xor1就等於+1或-1,那樣又會少了一些判斷,

並且,Dinic也可以做費用流,只要將廣搜換為SPFA就行了

完結撒花!!!??ヽ(°▽°)ノ?

題解 洛谷 P3376 【【模板】網絡最大流】