標籤:組成 img splay 表示 最小 TE namespace turn max
網路流是什嗎?
不急我們慢慢來講。
首先我們先看看最大流1.背景
管道網路中每條邊的最大通過能力(容量)是有限的,實際流量不超過容量。最大流問題(maximum flow problem),一種組合最佳化問題,就是要討論如何充分利用裝置的能力,使得運輸的流量最大,以取得最好的效果。求最大流的標號演算法最早由福特和福克遜與與1956年提出,20世紀50年代福特(Ford)、(Fulkerson)建立的“網路流理論”,是網路應用的重要組成成分。
2.定義(這很重要!!!)
1)源點:只有流出去的點
2)匯點:只有流進來的點
3)流量:一條邊上流過的流量
4)容量:一條邊上可供流過的最大流量
5)殘量:一條邊上的容量-流量
2.性質
1)對於任何一條流,總有流量<=容量(流經的邊的最小流量),即
\[flow<=min \left\{cur_{i}\right\}(cur_i\in flow_{now})\]
2)對於任何一條有向邊(u,v),總有
\[cur(u,v)=-cur(v,u)\]
3.演算法思想(增廣路dinic)
1.找到一條從源點到匯點的路徑,使得路徑上任意一條邊的殘量>0(注意是小於而不是小於等於,這意味著這條邊還可以分配流量),這條路徑便稱為增廣路
2.找到這條路徑上最小的\(F[u][v]\)(我們設\(F[u][v]\)表示\(u->v\)這條邊上的殘量即剩餘流量),下面記為\(flow\)
3.將這條路徑上的每一條有向邊\(u->v\)的殘量減去\(flow\),同時對於起反向邊\(v->u\)的殘量加上\(flow\)(為什麼呢?我們下面再講)
4.重複上述過程,直到找不出增廣路,此時我們就找到了最大流
這個圖很詳細的給出了增廣路的過程,其實這就是dinic演算法的思想
4.時間複雜度
dinic演算法其實就是一種暴力,時間複雜度
\[O(n^2m)\]
這其實十分暴力了,如果\(m=\frac{n(n-1)}{2}\)d的話,那麼時間複雜度將達到
\[O(\frac{n^3(n-1)}{2})\]
省略常數後也就是
\[O(n^4)\]
這是極其恐怖的複雜度,當然如果出題人不故意卡的話,一般沒什麼問題
5.代碼實現
#include<iostream>#include<cstdio>#include<cstring>#include<queue>#define Maxn 1000001#define INF 0x7fffffff#define maxN 1000001#define maxM 1000001using namespace std;class Dinic{ private: int cnt;//邊的數量,從0開始編號。 int head[Maxn];//每一個點最後一條邊的編號 int next[Maxn];//指向對應點的前一條邊 int v[Maxn];//每一條邊指向的點 int w[Maxn];//每一條邊的殘量 int n,s,t;//源點和匯點 int depth[Maxn];//分層圖中標記深度 void add_edge(int x,int y,int z){ next[++cnt]=head[x]; v[cnt]=y; w[cnt]=z; head[x]=cnt; return; } public: void init(int x,int y,int z){//初始化 n=x,s=y,t=z; cnt=-1; memset(head,-1,sizeof(head)); memset(next,-1,sizeof(next)); return; } void addedge(int x,int y,int z){ add_edge(x,y,z); add_edge(y,x,0); return; } bool bfs(){//廣搜找分層圖 queue<int>q; memset(depth,0,sizeof(depth)); depth[s]=1; q.push(s); do{ int u=q.front(); q.pop(); for(int i=head[u];~i;i=next[i]){ if(w[i]>0 and !depth[v[i]]){ depth[v[i]]=depth[u]+1; q.push(v[i]); } } }while(!q.empty()); return depth[t]; } int dfs(int u,int now){ if(u==t) return now; for(int i=head[u];~i;i=next[i]){ if(w[i]>0 and depth[v[i]]==depth[u]+1){ int d=dfs(v[i],min(now,w[i])); if(d>0){ w[i]-=d;w[i^1]+=d; return d; } } } return 0; } int dinic(){//dinic演算法主過程 int ans=0; while(bfs()){ int x; while(x=dfs(s,INF)) ans+=x; } return ans; }}dinic;int n,m,s,t;int main(){ scanf("%d%d%d%d",&n,&m,&s,&t); dinic.init(n,s,t); for(int i=1;i<=m;i++){ int x,y,z; scanf("%d%d%d",&x,&y,&z); dinic.addedge(x,y,z); } printf("%d\n",dinic.dinic()); return 0;}
6.最大流能解決的問題
網路流的問題其實有著很大的共性,首先就是他們都是只需要求一個的答案,且不需要中間的過程,還有答案是某種最值,往往這就是網路流。而網路流也不是裸的,往往需要各種建模亂搞。
演算法_dinic最大流