HDU3157:Crazy Circuits——题解

时间:2022-02-03 18:19:49

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=;
const int M=;
const int INF=;
inline int read(){
int X=,w=;char ch=;
while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
while(isdigit(ch))X=(X<<)+(X<<)+(ch^),ch=getchar();
return w?-X:X;
}
struct node{
int nxt,to,w;
}edge[M];
int head[N],du[N];
int cnt=-,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=;
for(int i=;i<=k;i++){
lev[i]=-;
cur[i]=head[i];
}
dui[]=S,lev[S]=;
int u,v;
for(int l=;l<=r;l++){
u=dui[l];
for(int e=head[u];e!=-;e=edge[e].nxt){
v=edge[e].to;
if(edge[e].w>&&lev[v]==-){
lev[v]=lev[u]+;
r++;
dui[r]=v;
if(v==T)return ;
}
}
}
return ;
}
int dinic(int u,int flow,int k){
if(u==k)return flow;
int res=,delta;
for(int &e=cur[u];e!=-;e=edge[e].nxt){
int v=edge[e].to;
if(edge[e].w>&&lev[u]<lev[v]){
delta=dinic(v,min(edge[e].w,flow-res),k);
if(delta>){
edge[e].w-=delta;
edge[e^].w+=delta;
res+=delta;
if(res==flow)break;
}
}
}
if(res!=flow)lev[u]=-;
return res;
}
inline void init(){
memset(head,-,sizeof(head));
memset(du,,sizeof(du));
cnt=-;
return;
}
inline int getc(){
char ch=getchar();
while(ch==' '||ch=='\n')ch=getchar();
if(ch=='+')return st;
if(ch=='-')return ed;
int X=;
while(isdigit(ch))X=(X<<)+(X<<)+(ch^),ch=getchar();
return X;
}
int main(){
int n,m;
while(scanf("%d%d",&n,&m)!=EOF){
if(n+m==)break;
init();
st=n+,ed=st+;
for(int i=;i<=m;i++){
int u=getc(),v=getc(),c=read();
add(u,v,INF-c);add(v,u,);
du[u]-=c;du[v]+=c;
}
int full=,ans=;
S=ed+;T=S+;
for(int i=;i<=ed;i++){
if(du[i]>){
add(S,i,du[i]);add(i,S,);
full+=du[i];
}else if(du[i]<){
add(i,T,-du[i]);add(T,i,);
}
}
while(bfs(T))ans+=dinic(S,INF,T);
add(ed,st,INF);add(st,ed,);
while(bfs(T))ans+=dinic(S,INF,T);
if(ans!=full)puts("impossible");
else{
printf("%d\n",edge[cnt].w);
}
}
return ;
}