LibreOJ #101.最大流

题目描述

这是一道模板题。

给定 个点, 条边,给定每条边的容量,求从点 s 到点 的最大流。

输入格式

第一行四个整数 n,m,s,t .
接下来的 行,每行三个整数 u,v,c ,表示 v ,流量为 c 的一条边。

输出格式

输出点 到点 的最大流。

样例

样例输入

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

样例输出

14

数据范围与提示

1⩽n⩽100,1⩽m⩽5000,0⩽c⩽2e31−1

题目注意

结果要用long long 保存,int会爆

AC代码

#include<iostream>
#include<queue>
#include<algorithm>
#include<cstdio>
using namespace std;
const int maxn = 110;
const int inf = 0x7fffffff;
struct Edge{
    int to, w, next;
};
Edge e[5000*2+10];
int depth[maxn];     //顶点的层数
int head[maxn];      //实现链式前向星
int cur[maxn];       //当前弧优化,cur就是记录当前点u循环到了哪一条边
int n, m, s, t;
int cnt;             //边的编号
void init(){
    cnt = 0;
    //s = 1, t = n;
    for (int i = 0; i <= n; i++) 
        head[i] = -1;
}
void add_edge(int u, int v, int w){  //加边
    e[cnt].to = v; e[cnt].w = w;
    e[cnt].next = head[u]; head[u] = cnt++;
}
int bfs(int s,int t){    //分层
    queue<int> q;
    for (int i = 0; i <= n; i++) depth[i] = inf;
    q.push(s);
    depth[s] = 0;
    while (!q.empty()){
        int p = q.front(); q.pop();
        for (int i = head[p]; ~i; i = e[i].next){  //遍历以p为起始的边
            if (e[i].w>0 && depth[p]+1<depth[e[i].to]){ //如果是可行边,并且下一个点的深度和当前点的深度相差大于1
                depth[e[i].to] = depth[p] + 1;    //更新下一个点的深度
                q.push(e[i].to);
            }
        }
    }
    return depth[t] != inf;
}
int dfs(int u,int flow){    //多次增广 当前点u和flow为当前流量,一开始假设为inf
    if (u == t)     //如果找到汇点
        return flow;
    for (int& i = cur[u]; ~i; i = e[i].next){    //----------修改部分
        if (e[i].w > 0 && depth[u] + 1 == depth[e[i].to]){
            int delta = dfs(e[i].to, min(flow,e[i].w));  //向下增广
            if (delta > 0){       //增广成功
                e[i].w -= delta;
                e[i ^ 1].w += delta; 
                return delta;     //向上传递
            }
        }

    }
    return 0;  //没有增广路,返回0
}

long long dinic(){   //dinic主体
    long long res = 0;
    while (bfs(s,t)){
        
        for (int i = 0; i <= n; i++) cur[i] = head[i];  //-------修改部分,注意每次初始化cur

        while (int delta = dfs(s,inf))
            res += 1ll*delta;
    }
    return res;
}
int main()
{
    ios::sync_with_stdio(false);
    cin >> n >> m>>s>>t;  //顶点数和边数
    init();
    int a, b, c;
    for (int i = 0; i < m; i++){
        cin >> a >> b >> c;
        add_edge(a, b, c);
        add_edge(b, a, 0);   //注意反向边初始为0
    }
    cout << dinic() << endl;
    
    return 0;
}
dinic+当前弧优化

 题解效率

 

posted @ 2019-03-02 16:12  looeyWei  阅读(429)  评论(0)    收藏  举报