HDU3157:Crazy Circuits——题解
http://acm.hdu.edu.cn/showproblem.php?pid=3157
题目大意:给一个电路 ,起点为+,终点为-,包括起点终点在内的电元件之间有有下界边,求最小流。
————————————————————————————————
上下界网络流完结之题,显然是要求最小流的。
(然而自从做了上下界网络流之后我发现网上的题解是真的坑……有的人样例都不过就敢把代码粘到网上,有的人最小流做法是错的……)
这里仍然推荐这个人的博客,至少是对的:https://www.cnblogs.com/kane0526/archive/2013/04/05/3001108.html
首先先和上下界最大流是一样的操作,只是我们先不建ed到st的inf的边,我们先跑一遍,等跑不动了之后再建再跑。
这样做显然可以先将环先跑完,然后再跑别的,有效减少ed到st的流量,进而减少最小流。
因此我们的最小流就是ed到st的inf的边的反边的流量。
#include<cstdio> #include<iostream> #include<cmath> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; const int N=105; const int M=1005; const int INF=2147483647; inline int read(){ int X=0,w=0;char ch=0; while(!isdigit(ch)){w|=ch=='-';ch=getchar();} while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar(); return w?-X:X; } struct node{ int nxt,to,w; }edge[M]; int head[N],du[N]; int cnt=-1,S,T,st,ed; inline void add(int u,int v,int w){ cnt++; edge[cnt].to=v; edge[cnt].w=w; edge[cnt].nxt=head[u]; head[u]=cnt; return; } int lev[N],cur[N],dui[N]; bool bfs(int k){ int r=0; for(int i=1;i<=k;i++){ lev[i]=-1; cur[i]=head[i]; } dui[0]=S,lev[S]=0; int u,v; for(int l=0;l<=r;l++){ u=dui[l]; for(int e=head[u];e!=-1;e=edge[e].nxt){ v=edge[e].to; if(edge[e].w>0&&lev[v]==-1){ lev[v]=lev[u]+1; r++; dui[r]=v; if(v==T)return 1; } } } return 0; } int dinic(int u,int flow,int k){ if(u==k)return flow; int res=0,delta; for(int &e=cur[u];e!=-1;e=edge[e].nxt){ int v=edge[e].to; if(edge[e].w>0&&lev[u]<lev[v]){ delta=dinic(v,min(edge[e].w,flow-res),k); if(delta>0){ edge[e].w-=delta; edge[e^1].w+=delta; res+=delta; if(res==flow)break; } } } if(res!=flow)lev[u]=-1; return res; } inline void init(){ memset(head,-1,sizeof(head)); memset(du,0,sizeof(du)); cnt=-1; return; } inline int getc(){ char ch=getchar(); while(ch==' '||ch=='\n')ch=getchar(); if(ch=='+')return st; if(ch=='-')return ed; int X=0; while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar(); return X; } int main(){ int n,m; while(scanf("%d%d",&n,&m)!=EOF){ if(n+m==0)break; init(); st=n+1,ed=st+1; for(int i=1;i<=m;i++){ int u=getc(),v=getc(),c=read(); add(u,v,INF-c);add(v,u,0); du[u]-=c;du[v]+=c; } int full=0,ans=0; S=ed+1;T=S+1; for(int i=1;i<=ed;i++){ if(du[i]>0){ add(S,i,du[i]);add(i,S,0); full+=du[i]; }else if(du[i]<0){ add(i,T,-du[i]);add(T,i,0); } } while(bfs(T))ans+=dinic(S,INF,T); add(ed,st,INF);add(st,ed,0); while(bfs(T))ans+=dinic(S,INF,T); if(ans!=full)puts("impossible"); else{ printf("%d\n",edge[cnt].w); } } return 0; }