【有源汇点上下界最小流】[SGU176]Flow construction

题目大意

给出N个点,M条有向边
如果有向边的标号是1的话,就表示该边的上界下界都为容量
如果有向边的标号为0的哈,表示该边的下界为0,上界为容量
现在问,从1到N的最小流是多少,并输出每条边的流量

分析

无源汇点上下界可行流那样建图,然后从SS->ST跑一次,然后t->s连一条容量为+∞的边,跑一次,t->s这条边的流量即为最小流。

代码

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#define INF 0x7f7f7f7f
#define MAXN 100
using namespace std;
int n,m,d[MAXN+10],S,T,num,dist[MAXN+10],vd[MAXN+10],tot,l[MAXN*MAXN+10],flow;
void Read(int &x){
    char c;
    while(c=getchar(),c!=EOF)
        if(c>='0'&&c<='9'){
            x=c-'0';
            while(c=getchar(),c>='0'&&c<='9')
                x=x*10+c-'0';
            ungetc(c,stdin);
            return;
        }
}
struct node{
    int v,cap;
    node *next,*back;
}*adj[MAXN+10],edge[MAXN*MAXN+10],*ecnt=edge,*epos[MAXN*MAXN+10];
void addedge(int u,int v,int cap,int pos){
    node *p=++ecnt;
    p->v=v;
    p->cap=cap;
    p->next=adj[u];
    epos[pos]=p;
    adj[u]=p;
    p=p->back=++ecnt;
    p->v=u;
    p->cap=0;
    p->next=adj[v];
    adj[v]=p;
    p->back=ecnt-1;
}
void read(){
    Read(n),Read(m);
    int i,u,v,z,c;
    for(i=1;i<=m;i++){
        Read(u),Read(v),Read(z),Read(c);
        if(c==1)
            d[u]-=z,d[v]+=z,epos[i]=0,l[i]=z;
        else
            addedge(u,v,z,i);
    }
    S=n+1,T=n+2;
    for(i=1;i<=n;i++)
        if(d[i]>0)
            addedge(S,i,d[i],0),tot+=d[i];
        else if(d[i]<0)
            addedge(i,T,-d[i],0);
}
int dfs(int u,int augu){
    if(u==T)
        return augu;
    int v,augv=0,delta,mind=num-1;
    for(node *p=adj[u];p;p=p->next)
        if(p->cap){
            v=p->v;
            if(dist[u]==dist[v]+1){
                delta=min(augu-augv,p->cap);
                delta=dfs(v,delta);
                augv+=delta;
                p->cap-=delta;
                p->back->cap+=delta;
                if(augu==augv||dist[S]>=num)
                    return augv;
            }
            mind=min(mind,dist[v]);
        }
    if(!augv){
        if(!--vd[dist[u]])
            dist[S]=num;
        dist[u]=mind+1;
        vd[dist[u]]++;
    }
    return augv;
}
void mcmf(){
    memset(dist,0,sizeof dist);
    memset(vd,0,sizeof vd);
    num=n+2;
    vd[0]=num;
    while(dist[S]<num)
        flow+=dfs(S,INF);
}
void print(){
    if(flow!=tot){
        puts("Impossible");
        return;
    }
    printf("%d\n",epos[m+1]->back->cap);
    for(int i=1;i<m;i++)
        if(epos[i])
            printf("%d ",epos[i]->back->cap);
        else
            printf("%d ",l[i]);
    if(epos[m])
        printf("%d\n",epos[m]->back->cap);
    else
        printf("%d\n",l[m]);
}
int main()
{
    read();
    mcmf();
    addedge(n,1,INF,m+1);
    mcmf();
    print();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值