网络流
Posted gcfer
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了网络流相关的知识,希望对你有一定的参考价值。
今天开始学网络流...
首先是bfs找通流的EK算法..
#include<bits/stdc++.h> using namespace std; const int N=10010,M=100010,qwq=1<<30; int link[N],tot=1,n,m,s,t,maxflow,vis[N],id,incf[N],pre[N]; struct edge{int y,v,next;}a[M<<1]; inline int read() { int x=0,ff=1; char ch=getchar(); while(!isdigit(ch)) {if(ch==‘-‘) ff=-1;ch=getchar();} while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*ff; } inline void add(int x,int y,int v) { a[++tot].y=y; a[tot].v=v; a[tot].next=link[x]; link[x]=tot; } inline bool bfs() { queue<int>q;q.push(s); id++;vis[s]=id;//标记源点 incf[s]=qwq;//初始化流量 while(q.size()) { int x=q.front();q.pop(); for(int i=link[x];i;i=a[i].next) { if(a[i].v)//如果当前的边有剩余流量 { int y=a[i].y; if(vis[y]==id) continue;//若已标记过,则退出. incf[y]=min(incf[x],a[i].v);//更新最小剩余流量 pre[y]=i;//记录点的前驱(记录的是边) q.push(y);vis[y]=id;//标记这个点 if(y==t) return true;//如果到达汇点,则返回true } } } return false; } inline void update() { int x=t;//从汇点出发. while(x!=s) { int i=pre[x];//找到来时的边 a[i].v-=incf[t];//这条边剩余容量减少 a[i^1].v+=incf[t];//边的反向边剩余容量增加 x=a[i^1].y;//退回到上一个点 } maxflow+=incf[t];//最大流量更新. } int main() { freopen("1.in","r",stdin); n=read(),m=read(),s=read(),t=read(); for(int i=1;i<=m;++i) { int x=read(),y=read(),v=read(); add(x,y,v);add(y,x,0);//反向边的边权为0 } while(bfs()) update(); printf("%d",maxflow); return 0; }
之后就是优化的dfs剪枝找通流dinic算法(现在还是好迷得.....):
#include<bits/stdc++.h> #define ll long long using namespace std; const int N=10010,M=100010,qwq=1<<30; int n,m,s,t,link[N],d[N],tot=1; ll maxflow; struct edge{int y,v,next;}a[M<<1]; inline int read() { int x=0,ff=1; char ch=getchar(); while(!isdigit(ch)) {if(ch==‘-‘) ff=-1;ch=getchar();} while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*ff; } inline void add(int x,int y,int v) { a[++tot].y=y; a[tot].v=v; a[tot].next=link[x]; link[x]=tot; } inline bool bfs() { queue<int>q;q.push(s); memset(d,0,sizeof(d)); d[s]=1;//初始化s的深度. while(!q.empty()) { int x=q.front();q.pop(); for(int i=link[x];i;i=a[i].next) { int y=a[i].y; if(a[i].v&&!d[y])//如果当前边有剩余流量且还没有便利过 { q.push(y); d[y]=d[x]+1; if(y==t) return true;//这里忽略了其他深度比t大的点,但其实 }//已经构成了从s到t的残余网络. } } return false; } inline int dinic(int x,int flow) { if(x==t) return flow; int rest=flow,k;//rest表示flow与k的差值. for(int i=link[x];i&&rest;i=a[i].next)//如果rest为0直接退出. { int y=a[i].y; if(a[i].v&&d[y]==d[x]+1) { k=dinic(y,min(rest,a[i].v));//k表示当前找到的最小流量. if(!k) d[y]=0;//如果k为0,直接将这个点删掉 a[i].v-=k; a[i^1].v+=k;//更新边权 rest-=k;//rest表示flow与k的差值 } } return flow-rest; } int main() { freopen("1.in","r",stdin); n=read();m=read();s=read();t=read(); for(int i=1;i<=m;++i) { int x=read(),y=read(),v=read(); add(x,y,v);add(y,x,0); } int flow=0; while(bfs())//构建残余网络 while(flow=dinic(s,qwq)) maxflow+=flow;//累加剩余流量. printf("%lld",maxflow); return 0; }
以上是关于网络流的主要内容,如果未能解决你的问题,请参考以下文章
此应用小部件片段中所有意图 (PendingIntents) 的逻辑流
VSCode自定义代码片段14——Vue的axios网络请求封装
VSCode自定义代码片段14——Vue的axios网络请求封装