HDU 6214 网络流

简略题意:n个点,m条边,问所有最小割中的最小边数是多少。

经典模型
最大流等于最小割,因此求出最大流即可知道最小割。
问题在于多个最小割时怎么办?
我们对每个边扩容,流量为w的变成w*BIG+1,BIG为一个足够大的容量。那么只有原图边数最小的最小割才是此时的最小割。
原图的最小割容量为ans/BIG,边数为ans%BIG。

#define others
#ifdef poj
#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
#endif // poj
#ifdef others
#include <bits/stdc++.h>
#endif // others
//#define file
#define all(x) x.begin(), x.end()
using namespace std;
const double eps = 1e-8;
int dcmp(double x) { if(fabs(x)<=eps) return 0; return (x>0)?1:-1;};
typedef long long LL;

struct Dinic {
    static const LL maxn = 1e6 + 10;
    static const LL maxm = 4e6 + 10;

    struct Edge {
        LL u, v, next, flow, cap;
    } edge[maxm*2];

    LL head[maxn], level[maxn], cur[maxn], eg;

    void AddEdge(LL u, LL v, LL cap) {
        edge[eg] = {u, v, head[u], 0, cap}, head[u] = eg++;
        swap(u, v);
        edge[eg] = {u, v, head[u], 0, 0}, head[u] = eg++;
    }

    void init() {
        eg = 0;
        memset(head, -1, sizeof head);
    }
    bool makeLevel(LL s, LL t, LL n) {
        for(LL i = 0; i < n; i++) level[i] = 0, cur[i] = head[i];
        queue<LL> q; q.push(s);
        level[s] = 1;
        while(!q.empty()) {
            LL u = q.front();
            q.pop();
            for(LL i = head[u]; ~i; i = edge[i].next) {
                Edge &e = edge[i];
                if(e.flow < e.cap && level[e.v] == 0) {
                    level[e.v] = level[u] + 1;
                    if(e.v == t) return 1;
                    q.push(e.v);
                }
            }
        }
        return 0;
    }
    LL findpath(LL s, LL t, LL limit = 1e18) {
        if(s == t || limit == 0) return limit;
        for(LL i = cur[s]; ~i; i = edge[i].next) {
            cur[edge[i].u] = i;
            Edge &e = edge[i], &rev = edge[i^1];
            if(e.flow < e.cap && level[e.v] == level[s] + 1) {
                LL flow = findpath(e.v, t, min(limit, e.cap - e.flow));
                if(flow > 0) {
                    e.flow += flow;
                    rev.flow -= flow;
                    return flow;
                }
            }
        }
        return 0;
    }
    LL operator()(LL s, LL t, LL n) {
        LL ans = 0;
        while(makeLevel(s, t, n)) {
            LL flow;
            while((flow = findpath(s, t)) > 0) ans += flow;
        }
        return ans;
    }
} dinic;

namespace solver {
    const LL maxn = 100011;
    LL cas;
    LL n, m, s, t;
    void solve() {
        scanf("%lld", &cas);
        for(LL _ = 0; _ < cas; _++) {
            scanf("%lld%lld", &n, &m);
            scanf("%lld%lld", &s, &t);
            dinic.init();
            LL MOD = 2560000;
            for(LL i = 1; i <= m; i++) {
                LL u, v, w;
                scanf("%lld%lld%lld", &u, &v, &w);
                dinic.AddEdge(u, v, w*MOD+1);
            }
            printf("%lld\n", dinic(s, t, n + 1)%MOD);
        }
    }
}

int main() {
    solver::solve();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值