题意:
给定一个有向网络,每条边均有一个容量。问是否存在一个从点1到点N,流量为C的流。如果不存在,是否可以恰好修改一条弧的容量,使得存在这样的流?
分析:
先跑一遍最大流,如果最大流大于等于C,则输possible。如果最大流小于C,则表明需要修改边的流量。很显然,需要修改的弧一定是满流的弧。但是如果直接暴力会超时,所以我们可以有两个优化。
1.第一次求完最大流以后,把每条弧的流量保存下来,每次修改完一条弧的容量以后,都从当前残量网络开始继续增广。
2.每次不需要增广到最大流,当流量大于等于C的时候就停止增广(不过不加这个优化好像也没事,反正我没加··)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <iostream> 5 #include <queue> 6 #include <vector> 7 8 using namespace std; 9 const int maxn=100+10; 10 const int maxm=20000+10; 11 const int INF=2147000000; 12 struct Dinic{ 13 int head[maxn],Next[maxm],to[maxm],from[maxm],cap[maxm],flow[maxm]; 14 int n,m,s,t,sz; 15 bool vis[maxn]; 16 int d[maxn],cur[maxn]; 17 void init(int n){ 18 this->n=n; 19 sz=-1; 20 memset(head,-1,sizeof(head)); 21 } 22 void add_edge(int a,int b,int c){ 23 ++sz; 24 to[sz]=b;Next[sz]=head[a];head[a]=sz; 25 cap[sz]=c;flow[sz]=0,from[sz]=a;; 26 ++sz; 27 to[sz]=a;Next[sz]=head[b];head[b]=sz; 28 cap[sz]=c;flow[sz]=c,from[sz]=b; 29 } 30 bool BFS(){ 31 memset(vis,0,sizeof(vis)); 32 for(int i=0;i<=n;i++)d[i]=INF; 33 queue<int>Q; 34 d[s]=0,vis[s]=1; 35 Q.push(s); 36 while(!Q.empty()){ 37 int u=Q.front();Q.pop(); 38 for(int i=head[u];i!=-1;i=Next[i]){ 39 int v=to[i]; 40 if(cap[i]>flow[i]&&!vis[v]){ 41 vis[v]=1; 42 d[v]=d[u]+1; 43 Q.push(v); 44 } 45 } 46 } 47 return vis[t]; 48 } 49 int DFS(int x,int a){ 50 if(x==t||a==0)return a; 51 int Flow=0,f; 52 for(int& i=cur[x];i!=-1;i=Next[i]){ 53 int v=to[i]; 54 if(d[v]==d[x]+1&&(f=DFS(v,min(a,cap[i]-flow[i])))>0){ 55 Flow+=f; 56 flow[i]+=f; 57 flow[i^1]-=f; 58 a-=f; 59 if(a==0)break; 60 } 61 } 62 return Flow; 63 } 64 int Maxflow(int s,int t){ 65 this->s=s;this->t=t; 66 int Flow=0; 67 while(BFS()){ 68 for(int i=0;i<=n;i++)cur[i]=head[i]; 69 Flow+=DFS(s,INF); 70 } 71 return Flow; 72 } 73 }dinic; 74 struct Edge{ 75 int from,to; 76 bool operator <(const Edge& rhs)const{ 77 return from<rhs.from||(from==rhs.from&&to<rhs.to); 78 } 79 }; 80 vector<Edge>ans; 81 int kase,N,E,C; 82 int main(){ 83 kase=0; 84 while(scanf("%d%d%d",&N,&E,&C)!=EOF&&(N||E||C)){ 85 ++kase; 86 printf("Case %d: ",kase); 87 ans.clear(); 88 dinic.init(N); 89 int u,v,c; 90 for(int i=1;i<=E;i++){ 91 scanf("%d%d%d",&u,&v,&c); 92 dinic.add_edge(u,v,c); 93 } 94 int Maxflow=dinic.Maxflow(1,N); 95 if(Maxflow>=C){ 96 printf("possible "); 97 }else{ 98 int FLOW[maxm]; 99 for(int i=0;i<=dinic.sz;i++){ 100 FLOW[i]=dinic.flow[i]; 101 } 102 int CAP,c=C-Maxflow; 103 for(int i=0;i<=dinic.sz;i+=2){ 104 if(dinic.cap[i]==dinic.flow[i]){ 105 106 for(int i=0;i<=dinic.sz;i++)dinic.flow[i]=FLOW[i]; 107 CAP=dinic.cap[i]; 108 dinic.cap[i]=C; 109 dinic.cap[i^1]=C; 110 Maxflow=dinic.Maxflow(1,N); 111 if(Maxflow>=c){ 112 ans.push_back((Edge){dinic.from[i],dinic.to[i]}); 113 } 114 dinic.cap[i]=CAP; 115 dinic.cap[i^1]=CAP; 116 for(int i=0;i<=dinic.sz;i++)dinic.flow[i]=FLOW[i]; 117 } 118 } 119 if(ans.size()==0){ 120 printf("not possible "); 121 }else{ 122 sort(ans.begin(),ans.end()); 123 printf("possible option:"); 124 for(int i=0;i<ans.size();i++){ 125 if(i!=0)printf(","); 126 printf("(%d,%d)",ans[i].from,ans[i].to); 127 } 128 printf(" "); 129 } 130 } 131 } 132 return 0; 133 }