AcWing 2188:无源汇上下界可行流 ← Dinic算法

​​【题目来源】
https://www.acwing.com/problem/content/2190/

【题目描述】
给定一个包含 n 个点 m 条边的有向图,每条边都有一个流量下界和流量上界。
求一种可行方案使得在所有点满足流量平衡条件的前提下,所有边满足流量限制。

【输入格式】
第一行包含两个整数 n 和 m。
接下来 m 行,每行包含四个整数 a,b,c,d 表示点 a 和 b 之间存在一条有向边,该边的流量下界为 c,流量上界为 d。
点编号从 1 到 n。

【输出格式】
如果存在可行方案,则第一行输出 YES,接下来 m 行,每行输出一个整数,其中第 i 行的整数表示输入的第 i 条边的流量。
如果不存在可行方案,直接输出一行 NO。
如果可行方案不唯一,则输出任意一种方案即可。

【输入样例一】
4 6
1 2 1 3
2 3 1 3
3 4 1 3
4 1 1 3
1 3 1 3
4 2 1 3

【输出样例一】
YES
1
2
3
2
1
1

【输入样例二】
4 6
1 2 1 2
2 3 1 2
3 4 1 2
4 1 1 2
1 3 1 2
4 2 1 2

【输出样例二】
NO

【数据范围】
1≤n≤200,
1≤m≤10200,
1≤a,b≤n,
0≤c≤d≤10000

【算法分析】
Dinic算法:https://blog.csdn.net/hnjzsyjyj/article/details/161317988

【算法代码一】
A[N] —— 流量平衡差数组,记录每个点“流入 - 流出”的差值,判断是否存在可行流。
此代码中的语句 edge_id[i]=idx, low[idx]=c; 很关键。

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
const int INF=0x3f3f3f3f;
const int N=2e2+5,M=2e5+5;
int h[N],e[M],ne[M],idx,f[M],low[M];
int q[N],cur[N],d[N],A[N];
int edge_id[M];
int n,m,S,T;

void add(int a,int b,int c) {
    f[idx]=c,e[idx]=b,ne[idx]=h[a],h[a]=idx++;
    f[idx]=0,e[idx]=a,ne[idx]=h[b],h[b]=idx++;
}

bool bfs() {
    memset(d,-1,sizeof d);
    int hh=0,tt=0;
    q[0]=S,d[S]=0;

    while(hh<=tt) {
        int u=q[hh++];
        for(int i=h[u]; ~i; i=ne[i]) {
            int v=e[i];
            if(d[v]==-1 && f[i]) {
                d[v]=d[u]+1;
                q[++tt]=v;
            }
        }
    }
    return d[T]!=-1;
}

int dfs(int u,int lim) {
    if(u==T) return lim;
    int flow=0;
    for(int i=cur[u]; ~i && flow<lim; i=ne[i]) {
        cur[u]=i;
        int v=e[i];
        if(d[v]==d[u]+1 && f[i]) {
            int t=dfs(v,min(f[i],lim-flow));
            if(!t) d[v]=-1;
            f[i]-=t,f[i^1]+=t,flow+=t;
        }
    }
    return flow;
}

LL dinic() {
    LL r=0,flow=0;
    while(bfs()) { //0~T
        for(int i=0; i<=T; i++) cur[i]=h[i];
        while(flow=dfs(S,INF)) r+=flow;
    }
    return r;
}

int main() {
    memset(h,-1,sizeof h);
    cin>>n>>m;
    S=0,T=n+1;
    for(int i=1; i<=m; i++) {
        int a,b,c,d;
        cin>>a>>b>>c>>d;
        edge_id[i]=idx, low[idx]=c;
        add(a,b,d-c);
        A[a]-=c,A[b]+=c;
    }

    int tot=0;
    for(int i=1; i<=n; i++) {
        if(A[i]>0) add(S,i,A[i]),tot+=A[i];
        else if(A[i]<0) add(i,T,-A[i]);
    }

    if(dinic()==tot) {
        cout<<"YES\n";
        for(int k=1; k<=m; k++) {
            int i=2*(k-1);
            cout<<f[i^1]+low[i]<<endl;
        }
    } else cout<<"NO\n";

    return 0;
}

/*
in:
4 6
1 2 1 3
2 3 1 3
3 4 1 3
4 1 1 3
1 3 1 3
4 2 1 3

out:
YES
1
2
3
2
1
1
*/

【算法代码二】

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
const int INF=0x3f3f3f3f;
const int N=2e2+5,M=2e5+5;
int h[N],e[M],ne[M],idx,f[M],low[M];
int q[N],cur[N],d[N],A[N];
int n,m,S,T;

void add(int a,int b,int c,int d) {
    e[idx]=b,ne[idx]=h[a],f[idx]=d-c,low[idx]=c,h[a]=idx++;
    e[idx]=a,ne[idx]=h[b],f[idx]=0,h[b]=idx++;
}

bool bfs() {
    memset(d,-1,sizeof d);
    int hh=0,tt=0;
    q[0]=S,d[S]=0;

    while(hh<=tt) {
        int u=q[hh++];
        for(int i=h[u]; ~i; i=ne[i]) {
            int v=e[i];
            if(d[v]==-1 && f[i]) {
                d[v]=d[u]+1;
                q[++tt]=v;
            }
        }
    }
    return d[T]!=-1;
}

int dfs(int u,int lim) {
    if(u==T) return lim;
    int flow=0;
    for(int i=cur[u]; ~i && flow<lim; i=ne[i]) {
        cur[u]=i;
        int v=e[i];
        if(d[v]==d[u]+1 && f[i]) {
            int t=dfs(v,min(f[i],lim-flow));
            if(!t) d[v]=-1;
            f[i]-=t,f[i^1]+=t,flow+=t;
        }
    }
    return flow;
}

LL dinic() {
    LL r=0,flow=0;
    while(bfs()) { //0~T
        for(int i=0; i<=T; i++) cur[i]=h[i];
        while(flow=dfs(S,INF)) r+=flow;
    }
    return r;
}

int main() {
    memset(h,-1,sizeof h);
    cin>>n>>m;
    S=0,T=n+1;
    for(int i=1; i<=m; i++) {
        int a,b,c,d;
        cin>>a>>b>>c>>d;
        add(a,b,c,d);
        A[a]-=c,A[b]+=c;
    }

    int tot=0;
    for(int i=1; i<=n; i++) {
        if(A[i]>0) add(S,i,0,A[i]),tot+=A[i];
        else if(A[i]<0) add(i,T,0,-A[i]);
    }

    if(dinic()==tot) {
        cout<<"YES\n";
        for(int k=1; k<=m; k++) {
            int i=2*(k-1);
            cout<<f[i^1]+low[i]<<endl;
        }
    } else cout<<"NO\n";

    return 0;
}

/*
in:
4 6
1 2 1 3
2 3 1 3
3 4 1 3
4 1 1 3
1 3 1 3
4 2 1 3

out:
YES
1
2
3
2
1
1
*/




【参考文献】
https://blog.csdn.net/hnjzsyjyj/article/details/161317988
https://blog.csdn.net/hnjzsyjyj/article/details/127179286
https://www.acwing.com/solution/content/61022/
 

posted @ 2026-05-27 14:03  Triwa  阅读(9)  评论(0)    收藏  举报