刘汝佳新书--训练指南
题意:给定一个有向网络,每条边均有一个容量。问是否存在一个从点1到点N,流量为C的流。如果不存在,是否可以恰好修改一条弧的容量,使得存在这样的流?
分析:先求一次最大流,如果流量至少为C,则直接输出possible,否则需要修改的弧一定是最小割里的弧。依次把这些弧的容量增加到C,然后再求最大流,看最大流量是否至少为C即可。
很可惜,这样写出来的程序会超时,还需要加两个重要的优化。第一个优化是求完最大流后把流量留着,以后每次在它的基础上增广,第二个优化是每次没必要求出最大流,增广到流量至少为C时就停下来。
// File Name: dinic.cpp // Author: zlbing // Created Time: 2013/3/2 16:55:44 #include<iostream> #include<string> #include<algorithm> #include<cstdlib> #include<cstdio> #include<set> #include<map> #include<vector> #include<cstring> #include<stack> #include<cmath> #include<queue> using namespace std; #define CL(x,v); memset(x,v,sizeof(x)); #define INF 0x3f3f3f3f #define LL long long #define MAXN 110 struct Edge{ int from,to,cap,flow; }; bool cmp(const Edge& a,const Edge& b){ return a.from < b.from || (a.from == b.from && a.to < b.to); } struct Dinic{ int n,m,s,t; vector<Edge> edges; vector<int> G[MAXN]; bool vis[MAXN]; int d[MAXN]; int cur[MAXN]; void init(int n){ this->n=n; for(int i=0;i<=n;i++)G[i].clear(); edges.clear(); } void AddEdge(int from,int to,int cap){ edges.push_back((Edge){from,to,cap,0}); edges.push_back((Edge){to,from,0,0}); m=edges.size(); G[from].push_back(m-2); G[to].push_back(m-1); } bool BFS(){ CL(vis,0); queue<int> Q; Q.push(s); d[s]=0; vis[s]=1; while(!Q.empty()){ int x=Q.front(); Q.pop(); for(int i=0;i<G[x].size();i++){ Edge& e=edges[G[x][i]]; if(!vis[e.to]&&e.cap>e.flow){ vis[e.to]=1; d[e.to]=d[x]+1; Q.push(e.to); } } } return vis[t]; } int DFS(int x,int a){ if(x==t||a==0)return a; int flow=0,f; for(int& i=cur[x];i<G[x].size();i++){ Edge& e=edges[G[x][i]]; if(d[x]+1==d[e.to]&&(f=DFS(e.to,min(a,e.cap-e.flow)))>0){ e.flow+=f; edges[G[x][i]^1].flow-=f; flow+=f; a-=f; if(a==0)break; } } return flow; } int Maxflow(int s,int t,int need){ this->s=s;this->t=t; int flow=0; while(BFS()){ CL(cur,0); flow+=DFS(s,INF); if(flow>need)return flow; } return flow; } //最小割割边 vector<int> Mincut(){ BFS(); vector<int> ans; for(int i=0;i<edges.size();i++){ Edge& e=edges[i]; if(vis[e.from]&&!vis[e.to]&&e.cap>0)ans.push_back(i); } return ans; } void Reduce(){ for(int i = 0; i < edges.size(); i++) edges[i].cap -= edges[i].flow; } void ClearFlow(){ for(int i = 0; i < edges.size(); i++) edges[i].flow = 0; } }; Dinic solver; int main(){ int N,E,C,cas=0; while(~scanf("%d%d%d",&N,&E,&C)) { if(!N)break; solver.init(N); int a,b,c; while(E--) { scanf("%d%d%d",&a,&b,&c); solver.AddEdge(a,b,c); } int flow=solver.Maxflow(1,N,INF); printf("Case %d: ",++cas); if(flow>C)printf("possible\n"); else{ vector<int> cut=solver.Mincut(); solver.Reduce(); vector<Edge>ans; for(int i=0;i<cut.size();i++){ Edge& e=solver.edges[cut[i]]; int temp=e.cap; e.cap=C; solver.ClearFlow(); if(flow+solver.Maxflow(1,N,C-flow)>=C)ans.push_back(e); e.cap=temp; } if(ans.empty())printf("not possible\n"); else{ sort(ans.begin(),ans.end(),cmp); printf("possible option:(%d,%d)",ans[0].from,ans[0].to); for(int i=1;i<ans.size();i++) printf(",(%d,%d)",ans[i].from,ans[i].to); printf("\n"); } } } return 0; }