最大流模板:
- 普通最大流
- 无向图限制:将无向图的边拆成2条方向相反的有向边
- 顶点有流量限制:拆成2个点,连接一条容量为点容量限制的边
- 无源汇点有最小流限制的最大流:理解为水管流量形成循环
- 有源汇点的最小流限制的最大流
- 有源汇点的最小流限制的最小流
- 容量为负数:不能直接利用最大流求边权为负数的最小割。不知道怎么具体处理。。。
模板使用Dinic分层算法,使用了当前弧优化,效率还是不错的,使用的是vector存图,如果使用邻接表存图效率应该会更高吧。
但是ispa算法的效率更高,采用了当前弧优化的ispa算法那就更更高的效率了(=^ ^=),但是这个算法目前不会啊。。。
#include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> #include<set> #include<map> #include<queue> #include<stack> #include<vector> using namespace std; typedef long long ll; typedef pair<int,int> P; #define PI acos(-1.0) const int maxn=1e5+100,maxm=1e5+100,inf=0x3f3f3f3f,mod=1e9+7; const ll INF=1e18+7; struct edge { int from,to,cap,flow; }; vector<edge>es; vector<int>G[maxn]; bool vis[maxn]; int dist[maxn]; int iter[maxn]; void init(int n) { for(int i=0; i<=n+10; i++) G[i].clear(); es.clear(); } void addedge(int from,int to,int cap) { es.push_back((edge) { from,to,cap,0 }); es.push_back((edge) { to,from,0,0 }); int x=es.size(); G[from].push_back(x-2); G[to].push_back(x-1); } bool BFS(int s,int t) { memset(vis,0,sizeof(vis)); queue <int> Q; vis[s]=1; dist[s]=0; Q.push(s); while(!Q.empty()) { int u=Q.front(); Q.pop(); for (int i=0; i<G[u].size(); i++) { edge &e=es[G[u][i]]; if (!vis[e.to]&&e.cap>e.flow) { vis[e.to]=1; dist[e.to]=dist[u]+1; Q.push(e.to); } } } return vis[t]; } int DFS(int u,int t,int f) { if(u==t||f==0) return f; int flow=0,d; for(int &i=iter[u]; i<G[u].size(); i++) { edge &e=es[G[u][i]]; if(dist[u]+1==dist[e.to]&&(d=DFS(e.to,t,min(f,e.cap-e.flow)))>0) { e.flow+=d; es[G[u][i]^1].flow-=d; flow+=d; f-=d; if (f==0) break; } } return flow; } int Maxflow(int s,int t) { int flow=0; while(BFS(s,t)) { memset(iter,0,sizeof(iter)); int d=0; while(d=DFS(s,t,inf)) flow+=d; } return flow; } int in[maxn],out[maxn]; int l[maxn]; int main() { int n,m; scanf("%d%d",&n,&m); /**有源汇点*/ int s,t; scanf("%d%d",&s,&t); memset(in,0,sizeof(in)); memset(out,0,sizeof(out)); init(n); for (int i=1; i<=m; i++) { int u,v,r; scanf("%d %d %d %d",&u,&v,&l[i],&r); out[u]+=l[i],in[v]+=l[i]; addedge(u,v,r-l[i]); } /**有源汇点有下界*/ addedge(t,s,inf); /**有下界添加新源点0,汇点n+1*/ int ss=0,tt=n+1; int sum=0; for(int i=1; i<=n; i++) { if(in[i]>out[i]) { addedge(ss,i,in[i]-out[i]); sum+=in[i]-out[i]; } else if(in[i]<out[i]) addedge(i,tt,out[i]-in[i]); } /**无下界直接用s,t求最大流*/ if(Maxflow(ss,tt)!=sum) puts("NO"); else { puts("YES"); /**有源汇点*/ int ans=-es[2*m+1].flow; es[2*m+1].flow=0; es[2*m].flow=0; es[2*m].cap=0; ans+=Maxflow(s,t);///ans-=Maxflow(t,s);///最小流 printf("%d\n",ans); /**无源汇点:可以理解成水管形成循环*/ for(int i=0; i<m*2; i+=2) printf("%d\n",es[i].flow+l[i/2+1]);///每根水管的流量情况 } return 0; }