洛谷-4722 【模板】最大流 加强版 / 预流推进

题目描述
给定 n 个点,m 条有向边,给定每条边的容量,求从点 s 到点 t 的最大流。
输入格式
第一行包含四个正整数n、m、s、t,用空格分隔,分别表示点的个数、有向边的个数、源点序号、汇点序号。
接下来m行每行包含三个正整数 u i 、 v i 、 c i u_i、v_i、c_i uivici​,用空格分隔,表示第iii条有向边从 u i u_i ui​出发,到达 v i v_i vi​,容量为 c i c_i ci
输出格式
一个整数,表示s到t的最大流

输入输出样例
输入 #1
7 14 1 7
1 2 5
1 3 6
1 4 5
2 3 2
2 5 3
3 2 2
3 4 3
3 5 3
3 6 7
4 6 5
5 6 1
6 5 1
5 7 8
6 7 7

输出 #1
14

输入 #2
10 16 1 2
1 3 2
1 4 2
5 2 2
6 2 2
3 5 1
3 6 1
4 5 1
4 6 1
1 7 2147483647
9 2 2147483647
7 8 2147483647
10 9 2147483647
8 5 2
8 6 2
3 10 2
4 10 2

输出 #2
8

说明/提示
1 ⩽ n ⩽ 1200 , 1 ⩽ m ⩽ 120000 , 1 ⩽ c ⩽ 2 31 − 1 1⩽n⩽1200,1⩽m⩽120000,1⩽c⩽2^{31}−1 1n1200,1m120000,1c2311

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using std::min;
using std::vector;
using std::queue;
using std::priority_queue;
const int N=2e4+5,M=2e5+5,inf=0x3f3f3f3f;
int n,s,t,tot;
int v[M<<1],w[M<<1],first[N],next[M<<1];
int h[N],e[N],gap[N<<1],inq[N];//节点高度是可以到达2n-1的
struct cmp{
    inline bool operator()(int a,int b) const{
        return h[a]<h[b];//因为在优先队列中的节点高度不会改变,所以可以直接比较
    }
};
queue<int> Q;
priority_queue<int,vector<int>,cmp> pQ;
inline void add_edge(int from,int to,int flow){
    tot+=2;
    v[tot+1]=from;v[tot]=to;w[tot]=flow;w[tot+1]=0;
    next[tot]=first[from];first[from]=tot;
    next[tot+1]=first[to];first[to]=tot+1;
    return;
}
inline bool bfs(){
    int now;
    register int go;
    memset(h+1,0x3f,sizeof(int)*n);
    h[t]=0;Q.push(t);
    while(!Q.empty()){
        now=Q.front();Q.pop();
        for(go=first[now];go;go=next[go]) if(w[go^1]&&h[v[go]]>h[now]+1) h[v[go]]=h[now]+1,Q.push(v[go]);
    }
    return h[s]!=inf;
}
inline void push(int now){
    int d;
    register int go;
    for(go=first[now];go;go=next[go])
        if(w[go]&&h[v[go]]+1==h[now]){
            d=min(e[now],w[go]);
            w[go]-=d;w[go^1]+=d;e[now]-=d;e[v[go]]+=d;
            if(v[go]!=s&&v[go]!=t&&!inq[v[go]]) pQ.push(v[go]),inq[v[go]]=1;
            if(!e[now]) break;
        }
    return;
}
inline void relabel(int now){
    register int go;
    h[now]=inf;
    for(go=first[now];go;go=next[go]) if(w[go]&&h[v[go]]+1<h[now]) h[now]=h[v[go]]+1;
    return;
}
inline int hlpp(){
    int now,d;
    register int i,go;
    if(!bfs()) return 0;
    h[s]=n;
    memset(gap,0,sizeof(int)*(n<<1));
    for(i=1;i<=n;i++) if(h[i]<inf) ++gap[h[i]];
    for(go=first[s];go;go=next[go])
        if(d=w[go]){
            w[go]-=d;w[go^1]+=d;e[s]-=d;e[v[go]]+=d;
            if(v[go]!=s&&v[go]!=t&&!inq[v[go]]) pQ.push(v[go]),inq[v[go]]=1;
        }
    while(!pQ.empty()){
        inq[now=pQ.top()]=0;pQ.pop();push(now);
        if(e[now]){
            if(!--gap[h[now]]) for(i=1;i<=n;i++) if(i!=s&&i!=t&&h[i]>h[now]&&h[i]<n+1) h[i]=n+1;
            relabel(now);++gap[h[now]];
            pQ.push(now);inq[now]=1;
        }
    }
    return e[t];
}
int m;
signed main(){
    int u,v,w;
    scanf("%d%d%d%d",&n,&m,&s,&t);
    while(m--){
        scanf("%d%d%d",&u,&v,&w);
        add_edge(u,v,w);
    }
    printf("%d\n",hlpp());
    return 0;
}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值