POJ 3801/HDU 3157 Crazy Circuits | 有下界的最小流
题目:
POJ最近总是炸
所以还是用HDU吧http://acm.hdu.edu.cn/showproblem.php?pid=3157
题解:
题很长,但其实就是给个有源汇带下界网络流(+是源,-是汇),求最小流
求法:
1.模仿可行流建图,但是不加t到s的INF边
2.跑最大流
3.加t到sINF边
4.跑最大流
5.如果两次答案相加不等于sum,无解;
6.如果有解,t到s的反边流量就是答案
#include<cstdio> #include<algorithm> #include<cstring> #include<queue> #define N 205 #define M 20005 #define INF 0x3f3f3f3f using namespace std; int n,m,s,t,S,T,c,cur[N],head[N],d[N],sum,ecnt=1,ans,lev[N]; char a[N],b[N]; queue<int> q; struct adj { int nxt,v,w; }e[M]; int calc(char j[]) { if (j[0]=='+') return n+1; if (j[0]=='-') return n+2; int ans=0,s=strlen(j); for (int i=0;i<s;i++) ans*=10,ans+=j[i]-'0'; return ans; } void add(int u,int v,int w) { e[++ecnt].v=v;e[ecnt].w=w;e[ecnt].nxt=head[u];head[u]=ecnt; e[++ecnt].v=u;e[ecnt].w=0;e[ecnt].nxt=head[v];head[v]=ecnt; } void init() { memset(head,0,sizeof(head)); memset(d,0,sizeof(d)); ecnt=1;ans=sum=0; } bool bfs() { for (int i=1;i<=T;i++) cur[i]=head[i],lev[i]=-1; q.push(S);lev[S]=1; while (!q.empty()) { int u=q.front();q.pop(); for (int i=head[u],v;i;i=e[i].nxt) if (lev[v=e[i].v]==-1 && e[i].w>0) q.push(v),lev[v]=lev[u]+1; } return lev[T]!=-1; } int dfs(int u,int flow) { if (u==T) return flow; int ret=0,v,delta; for (int &i=cur[u];i;i=e[i].nxt) if (lev[v=e[i].v]==lev[u]+1 && e[i].w>0) { delta=dfs(v,min(flow-ret,e[i].w)); if (delta) { e[i].w-=delta;e[i^1].w+=delta;ret+=delta; if (ret==flow) break; } } return ret; } int main() { while (scanf("%d%d",&n,&m)!=EOF) { if (n==0 && m==0) break; init(); s=n+1;t=s+1;S=t+1;T=S+1; for (int i=1,u,v;i<=m;i++) { scanf("%s%s%d",a,b,&c); u=calc(a);v=calc(b); add(u,v,INF-c); d[u]-=c;d[v]+=c; } for (int i=1;i<=n+2;i++) if (d[i]>0) add(S,i,d[i]),sum+=d[i]; else if (d[i]<0) add(i,T,-d[i]); while (bfs()) ans+=dfs(S,INF); add(t,s,INF); while (bfs()) ans+=dfs(S,INF); if (ans!=sum) puts("impossible"); else printf("%d\n",e[ecnt].w); } return 0; }