【文文殿下】网络流学习笔记
生活随笔
收集整理的這篇文章主要介紹了
【文文殿下】网络流学习笔记
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
最大流算法
Dinic
割
一個(gè)網(wǎng)絡(luò)的割:存在一個(gè)邊集,刪去集合里的邊時(shí),S-T不再連通
最小割
所有割中邊權(quán)之和最小的
最小割-最大流定理
最小割等于最大流
二分圖匹配
\(M\)為邊集\(E\)的一個(gè)子集,如果對(duì)于任何一個(gè)點(diǎn),都最多被\(M\)中一條邊覆蓋,則成\(M\)為一個(gè)匹配。
最大匹配
使\(|M|\)最大的一個(gè)匹配(可能有多個(gè))
最大匹配求法
源點(diǎn)S向所有X連邊,Y向T連邊,容量均為1,原始圖上邊容量均為1,最大流=最大匹配。
二分圖最小頂點(diǎn)覆蓋
\(V'\)是點(diǎn)集\(V\)的一個(gè)子集,對(duì)于任意一條邊,至少有一端在\(V'\)內(nèi)。
最小的一個(gè)\(V'\)被稱作最小頂點(diǎn)覆蓋
最大匹配=最小頂點(diǎn)覆蓋
證明:若有一條邊未覆蓋,則匹配+1,與最大匹配矛盾
二分圖最大獨(dú)立集
\(V'\)是\(G\)的一個(gè)獨(dú)立集,當(dāng)且僅當(dāng)對(duì)于任何一條邊,它至少有一端不在\(V'\)內(nèi)
最大獨(dú)立集大小等于\(|V|-\)最大匹配
證明:最小割。若(S,x)為割邊,則在\(V'\)中刪去x。y同理。
有向圖最小路徑覆蓋
用盡可能少的簡(jiǎn)單路徑覆蓋整張圖。特殊的:一個(gè)點(diǎn)也是一條簡(jiǎn)單路徑。
二分圖建模:把每個(gè)點(diǎn)\(x\)拆成\(x_1,x_2\),分別屬于X,Y.
對(duì)原圖一條邊,(x,y),鏈接(\(x_1,y_2\))
易證:最小路徑覆蓋=\(|V|-\)最大匹配。
X中未被匹配的點(diǎn)是每條路徑的起點(diǎn)
二分圖點(diǎn)權(quán)最大獨(dú)立集
最大權(quán)獨(dú)立集=\(\sum value(x) -\)最小權(quán)頂點(diǎn)覆蓋
最小權(quán)覆蓋=最大匹配=最小割=最大流(原圖的邊流量為無窮大)
建圖:S向所有X連邊,容量為value(x),所有的Y向T連邊,容量為value(y) ,原圖中的邊容量為無窮大
最大權(quán)閉合子圖
\(U\)是\(G\)的一個(gè)子圖,x屬于\(U\) 當(dāng)且僅當(dāng)對(duì)于任何一條邊(x,y),y也屬于\(U\),那么\(U\)是\(G\)的一個(gè)閉合子圖
權(quán)值和最大的閉合子圖稱為最大權(quán)閉合子圖(權(quán)值有正有負(fù))
求法:建立源點(diǎn)S,向所有x(value(x)>0)連邊,容量為value(x),建立匯點(diǎn)T,所有y(value(y)<0)向T連邊,容量為-value(y),對(duì)于原圖中的邊(x,y),在x,y之間連一條容量為無窮大的邊。
最大權(quán)閉合子圖=\(\sum_{value(x)>0} value(x) -\) 最小割
證明:
若選了一個(gè)點(diǎn)x,則他的后繼一定會(huì)選(最大流),滿足閉合子圖。
若一個(gè)(S,x)為割邊,說明(S,x)滿流,則選了x,他的后繼付出的代價(jià)一定不小于x的權(quán)值,即x的貢獻(xiàn)小于等于0
有節(jié)點(diǎn)容量的最大流
建圖:對(duì)于每一個(gè)點(diǎn)x拆成兩個(gè)點(diǎn)\(x_1,x_2\),對(duì)于所有入邊,鏈接\(x_1\)出邊從\(x_2\)出,\(x_1,x_2\)之間鏈接一條容量為節(jié)點(diǎn)容量的邊
上下界網(wǎng)絡(luò)流
每條邊有流量上界和流量下界
建圖:先建新源點(diǎn)S1,新匯點(diǎn)T1,對(duì)于一條邊(x,y) ,從x到y(tǒng)連一條\(c(e)-l(e)\)的邊,從S1向y連一條\(l(e)\)的邊,從x向T1連一條\(l(e)\)的邊。
建一條從T到S容量為k的邊。
存在可行流:從S1出發(fā)的所有邊都滿流。
最小流:二分K,存在可行流,最小的K即為最小流
最大流:先跑可行流。跑完以后,把自己加入的必要弧刪去,再恢復(fù)源匯,嘗試增廣S-T
費(fèi)用流
算法:ZKW費(fèi)用流
板子
最大流(BZOJ1694)
#include<cstdio> #include<cstring> #include<queue> const int maxn = 1010; const int maxm = 2e5+10; const int inf = 0x3f3f3f3f; int n,k,S,T,wet[maxm],nxt[maxm],to[maxm],hd[maxn],cnt=1,dis[maxn],cur[maxn]; std::queue<int> Q; inline void add(int u,int v,int w) {nxt[++cnt]=hd[u];hd[u]=cnt;to[cnt]=v;wet[cnt]=w; } inline bool bfs(void) {for(int i = 0;i<=T;++i) cur[i]=hd[i];memset(dis,0,sizeof dis);dis[S]=1;Q.push(S);while(!Q.empty()) {int u = Q.front();Q.pop();for(int i = hd[u];i;i=nxt[i]){ int nx = to[i];if(!dis[nx]&&wet[i]>0) {dis[nx]=dis[u]+1;Q.push(nx);}}}return dis[T]!=0; } inline int dfs(int u,int flow) {if(u==T) return flow;int tmp = 0;for(int &i = cur[u];i;i=nxt[i]) {int nx = to[i];if(dis[nx]==dis[u]+1&&wet[i]>0) {int ret = dfs(nx,std::min(flow,wet[i]));if(ret<0) ret=0;flow-=ret;tmp+=ret;wet[i]-=ret;wet[i^1]+=ret;if(flow==0) break;}}return tmp; } inline int dinic(void) {int flow = 0;while(bfs()) {flow+=dfs(S,inf);}return flow; } int main() {scanf("%d%d",&n,&k);for(int i = 0;i<k;++i) {int x,y;scanf("%d%d",&x,&y);add(x,n+y,1);add(n+y,x,0);}S = 0;T = n+n+1;for(int i = 1;i<=n;++i) {add(S,i,1);add(i,S,0);}for(int i = n+1;i<=n+n;++i) {add(i,T,1);add(T,i,0);}printf("%d",dinic());return 0; }費(fèi)用流
#include<cstdio> #include<cstring> #include<queue> typedef long long ll; const int maxn = 5050,maxm=1e5+10; const int inf = 0x3f3f3f3f; int n,m,S,T,cnt=1,wet[maxm],fee[maxm],hd[maxn],nxt[maxm],to[maxm]; int dis[maxn],cur[maxn]; bool vis[maxn]; std::queue<int> Q; inline void add(int u,int v,int w,int f) {nxt[++cnt]=hd[u];to[cnt]=v;wet[cnt]=w;fee[cnt]=f;hd[u]=cnt; } inline bool spfa(void) {memset(dis , 0x3f3f3f3f , sizeof dis);memset(vis, 0 , sizeof vis);for(int i = 1;i<=n;++i) cur[i]=hd[i];Q.push(S);dis[S]=0;while(!Q.empty()) {int u = Q.front();Q.pop();vis[u]=0;for(int i = hd[u];i;i=nxt[i]) {int nx = to[i];if(dis[nx]>dis[u]+fee[i]&&wet[i]) {dis[nx]=dis[u]+fee[i];if(!vis[nx]) {Q.push(nx);vis[nx]=1;}}}}return dis[T]!=dis[0]; } inline int dfs(int u,int c,int &flow ,ll &ans) {vis[u]=1;if(u==T) {flow+=c;ans+=dis[u]*c;return c;}int tmp = 0;for(int &i = cur[u];i;i=nxt[i]) {int nx = to[i];if(!vis[nx]&&wet[i]>0&&dis[nx]==dis[u]+fee[i]) {int t = dfs(nx,std::min(c,wet[i]),flow,ans);wet[i]-=t;wet[i^1]+=t;tmp+=t;c-=t;}}return tmp; } inline void dinic(void) {int flow = 0;ll ans = 0;while(spfa()) {vis[T]=1;while(vis[T]) {vis[T]=0;dfs(S,inf,flow,ans);}}printf("%d %lld\n",flow,ans);return; } int main() {scanf("%d%d%d%d",&n,&m,&S,&T);for(int i = 0;i<m;++i) {int u,v,w,f;scanf("%d%d%d%d",&u,&v,&w,&f);add(u,v,w,f);add(v,u,0,-f);}dinic();return 0; }轉(zhuǎn)載于:https://www.cnblogs.com/Syameimaru/p/10117145.html
總結(jié)
以上是生活随笔為你收集整理的【文文殿下】网络流学习笔记的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java基础IO流(五)RandomAc
- 下一篇: redis设置开机自启动