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;
}

优质内容筛选与推荐>>
1、【转】Visual C++ 2008 sp1的新功能
2、模运算——大整数取模、幂取模等
3、SpringBoot启动报错Failed to determine a suitable driver class
4、silverlight视频、音频
5、JavaWeb_(SpringMVC框架)测试SpringMVC&Spring&MyBatis三大整合


长按二维码向我转账

受苹果公司新规定影响,微信 iOS 版的赞赏功能被关闭,可通过二维码转账支持公众号。

    阅读
    好看
    已推荐到看一看
    你的朋友可以在“发现”-“看一看”看到你认为好看的文章。
    已取消,“好看”想法已同步删除
    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号