XiaoHuang's Space
XiaoHuang's Space
XiaoHuang
May the force be with you.
『题解』洛谷P3376 【模板】网络最大流
Posted: Dec 11, 2019
Last Modified: Dec 13, 2019
This article was last modified days ago. The content of this post may be outdated!

Portal

Portal1:Luogu

Description

如题,给出一个网络图,以及其源点和汇点,求出其网络最大流。

Input

第一行包含四个正整数$N,M,S,T$,分别表示点的个数,有向边的个数,源点序号,汇点序号。

接下来$M$行每行包含三个正整数$u_i,v_i,w_i$,表示第$i$条有向边从$w_i$出发,到达$v_i$,边权为$w_i$(即该边最大流量为$w_i$)。

Output

一行,包含一个正整数,即为该网络的最大流。

Sample Input

4 5 4 3
4 2 30
4 3 20
2 3 20
2 1 30
1 3 40

Sample Output

50

Hint

数据规模:

对于$30\%$的数据:$N \leq 10,M \leq 25$;

对于$70\%$的数据:$N \leq 200,M \leq 1000$;

对于$100\%$的数据:$N \leq 10000,M \leq 100000$。

样例说明:

题目中存在$3$条路径:

$4 \to 2 \to 3$,该路线可通过$20$的流量

$4 \to 3$,可通过$20$的流量

$4 \to 2 \to 1 \to 3$,可通过$10$的流量(边$4 \to 2$之前已经耗费了$20$的流量)

故流量总计$20+20+10=50$,输出$50$。

Solution

模板题,求最大流。

Code

Emonds Karp(EK)算法
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>

using namespace std;

const int INF=0x3f3f3f3f, MAXN=10005, MAXM=200005;
int n, m, s, t, u, v, val, cnt, head[MAXN], dis[MAXN], pre[MAXN];
queue<int> Q;
struct node {
    int u, v, val, flow, nxt;
} edge[MAXM];
inline void addedge(int u, int v, int w) {//前向星存图
    edge[++cnt].u=u; edge[cnt].v=v; edge[cnt].val=w; edge[cnt].nxt=head[u]; head[u]=cnt;
}
inline bool Emonds_Karp() {
    memset(pre, 0, sizeof(pre));
    memset(dis, 0, sizeof(dis));//初始化
    dis[s]=INF;
    pre[s]=0;
    Q.push(s);
    while(!Q.empty()) {//类似于SPFA
        int x=Q.front();
        Q.pop();
        for (int i=head[x]; i; i=edge[i].nxt) {
            int v=edge[i].v;
            if (!dis[v] && edge[i].val>edge[i].flow) {
                Q.push(v);
                dis[v]=min(dis[x], edge[i].val-edge[i].flow);
                pre[v]=i;
            }
            if (dis[t]) break;
        }
    }
    return dis[t];
}
int main() {
    scanf("%d%d%d%d",&n, &m, &s, &t);
    cnt=1;
    for(int i=1; i<=m; i++) {
        scanf("%d%d%d",&u, &v, &val);
        addedge(u, v, val);
        addedge(v, u, 0);//前向星存图
    }
    int ans=0;
    while (Emonds_Karp()) {//Emonds Karp算法
        for (int i=t; i!=s; i=edge[pre[i]].u) {
            edge[pre[i]].flow+=dis[t];
            edge[pre[i] xor 1].val-=dis[t];
        }
        ans+=dis[t];
    }
    printf("%d\n",ans);
    return 0;
}
Dinic算法
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>

using namespace std;

const int INF=0x3f3f3f3f, MAXN=10005, MAXM=200005;
struct node {
    int nxt, to, val;
} edge[MAXM];
queue<int> Q;
int n, m, s, t, u, v, cnt, val, dis[MAXN], head[MAXN];
inline void addedge(int u, int v, int w) {//前向星存图
    edge[++cnt].val=w; edge[cnt].to=v; edge[cnt].nxt=head[u]; head[u]=cnt;
}
inline bool bfs() {
    memset(dis, -1, sizeof(dis));
    dis[s]=0;
    Q.push(s);
    while (!Q.empty()) {
        int x=Q.front();
        Q.pop();
        for (int i=head[x]; ~i; i=edge[i].nxt) {
            int v=edge[i].to;
            if (edge[i].val && dis[v]==-1) {
                dis[v]=dis[x]+1;
                Q.push(v);
            }
        }
    }
    if (~dis[t]) return 1;
    return 0;
}
inline int dfs(int u, int flow) {
    if (u==t) return flow;
    int ret=flow;
    for (int i=head[u]; ~i; i=edge[i].nxt) {
        if (ret<=0) break;
        int v=edge[i].to;
        if (edge[i].val && dis[v]==dis[u]+1) {
            int x=dfs(v, min(edge[i].val, ret));
            ret-=x;
            edge[i].val-=x;
            edge[i xor 1].val+=x;
        }
    }
    return flow-ret;
}
inline int Dinic() {//Dinic算法
    int ret=0;
    while (bfs()) ret+=dfs(s, INF);
    return ret;
}
int main() {
    scanf("%d%d%d%d",&n, &m, &s, &t);
    memset(head, -1, sizeof(head));
    cnt=1;
    for (int i=1; i<=m; i++) {
        scanf("%d%d%d",&u, &v, &val);
        addedge(u, v, val);
        addedge(v, u, 0);//双边
    }
    printf("%d\n",Dinic());
    return 0;
}
Improved Shortest Augmenting Path(ISAP)算法
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>

using namespace std;

const int INF=0x3f3f3f3f, MAXN=10005, MAXM=200005;
queue<int> Q;
int n, m, s, t, u, v, val, cnt, ans, head[MAXN], head1[MAXN], deep[MAXN], pre[MAXN], a[MAXN];
struct node {
    int v, w, nxt;
} edge[MAXM];
inline void addedge(int u, int v, int w) {//前向星存图
    edge[cnt].v=v; edge[cnt].w=w; edge[cnt].nxt=head[u]; head[u]=cnt++;
}
inline void bfs(int t) {
    for (int i=1; i<=n; i++)
        head1[i]=head[i];
    for (int i=1; i<=n; i++)
        deep[i]=n;
    deep[t]=0;
    Q.push(t);
    while (!Q.empty()) {
        int u=Q.front();
        Q.pop();
        for (int i=head[u]; ~i; i=edge[i].nxt)
            if (deep[edge[i].v]==n && edge[i^1].w) {
                deep[edge[i].v]=deep[u]+1;
                Q.push(edge[i].v);
            }
    }
}
int calc(int s,int t) {//计算
    int ans=INF, u=t;
    while (u!=s) {
        ans=min (ans,edge[pre[u]].w);
        u=edge[pre[u] xor 1].v;
    }
    u=t;
    while (u!=s) {
        edge[pre[u]].w-=ans;
        edge[pre[u] xor 1].w+=ans;
        u=edge[pre[u] xor 1].v;
    }
    return ans;
}
inline void ISAP(int s, int t) {//ISAP算法
    int u=s;
    bfs(t);
    for (int i=1; i<=n; i++)
        a[deep[i]]++;
    while (deep[s]<n) {
        if (u==t) {
            ans+=calc(s, t);
            u=s;
        }
        bool flag=0;
        for (int &i=head1[u]; ~i; i=edge[i].nxt)
            if (deep[u]==deep[edge[i].v]+1 && edge[i].w) {
                flag=1;
                u=edge[i].v;
                pre[edge[i].v]=i;
                break;
            }
        if (!flag) {
            int Min=n-1;
            for (int i=head[u]; ~i; i=edge[i].nxt)
                if (edge[i].w) Min=min(Min, deep[edge[i].v]);
            if ((--a[deep[u]])==0) break;
            a[deep[u]=Min+1]++;
            head1[u]=head[u];
            if (u!=s) u=edge[pre[u] xor 1].v;
        }
    }
}
int main() {
    memset(head, -1, sizeof (head));
    scanf("%d%d%d%d",&n, &m, &s, &t);
    for (int i=1; i<=m; i++) {
        scanf("%d%d%d",&u, &v, &val);
        addedge(u, v, val);
        addedge(v, u, 0);//双边
    }
    ISAP(s, t);
    printf ("%d\n",ans);
    return 0;
}
Article License: CC BY-NC-ND 4.0
Article Author: XiaoHuang
  1. 1. Portal
  2. 2. Description
  3. 3. Input
  4. 4. Output
  5. 5. Sample Input
  6. 6. Sample Output
  7. 7. Hint
  8. 8. Solution
  9. 9. Code
Newer Post
「Luogu 1412」经营与开发
Older Post
『题解』洛谷P4016 负载平衡问题
Buy me a beer?
-->
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×