2236. 伊基的故事 I - 道路重建

原题链接

  • 题意:给一个流网络,问有多少条边,使得增加他们容量可以增加最大流。
  • 题解:就是先跑出最大可行流,首先 \(f(u, v) \neq 0\),那么这条边不可以作为,显然其实感性理解就可以了。然后再枚举边,看看边的左端点是否存在一条路径从源点到左端点,边的右端点是否存在一条路径从右端点到汇点,如果都成立并且 \(f(u, v) = 0\) 那么这条边就可对答案做出贡献。
  • 代码:
#include <iostream>
#include <queue>
#include <cstring>
using namespace std;
const int N = 1e5, M = 1e6, inf = 99999999;
int h[N], to[M], f[M], ne[M], idx;
void add(int u, int v, int w) {
    ne[idx] = h[u], to[idx] = v, f[idx] = w, h[u] = idx++;
    ne[idx] = h[v], to[idx] = u, f[idx] = 0, h[v] = idx++;
}
int S, T;
int d[N], cur[N];
queue<int>q;
bool bfs() {
    while (!q.empty())q.pop();
    q.push(S);
    memset(d, -1, sizeof d);
    cur[S] = h[S];
    d[S] = 0;
    while (!q.empty()) {
        auto u = q.front();q.pop();
        for (int i = h[u]; ~i; i = ne[i]) {
            int v = to[i];
            if (d[v] == -1 && f[i]) {
                cur[v] = h[v];
                q.push(v);
                d[v] = d[u] + 1;
                if (v == T)return 1;
            }
        }
    }
    return 0;
}
int dfs(int u, int limit) {
    if (u == T)return limit;
    int flow = 0;
    for (int i = cur[u]; ~i; i = ne[i]) {
        int v = to[i];
        cur[u] = i;
        if (d[v] == d[u] + 1 && f[i]) {
            int t = dfs(v, min(f[i], limit - flow));
            flow += t;
            f[i] -= t;
            f[i ^ 1] += t;
        }
    }
    return flow;
}
int dinic() {
    int ret =0 , flow;
    while (bfs()) {//cout << "?";
        while (flow = dfs(S, inf))
            ret += flow;
    }
    return ret;
}

bool vis[2][N];
void dfs1(int u,int op) {
    vis[op][u] = 1;
    for (int i = h[u]; ~i; i = ne[i]) {
        int v = to[i];
        int j = op ^ i;
        if (f[j] && !vis[op][v]) {
            dfs1(v, op);
        }
    }
}
int main() {
    int n, m;
    scanf("%d%d", &n, &m);
    memset(h, -1, sizeof h);
    T = n-1;
    for (int i = 1; i <= m; i ++) {
        int u, v, w;scanf("%d%d%d", &u, &v, &w);
        add(u, v, w);
    }
    int x = dinic();
    dfs1(S, 0);
    dfs1(T, 1);
    int ans = 0;
    for (int i = 0; i < m * 2; i  += 2) {
        int u = to[i ^ 1];
        int v = to[i];
        if (f[i] == 0 && vis[0][u] && vis[1][v]) {
            ans++;
        }
    }
    printf("%d\n", ans);
}

posted @ 2021-04-14 12:06  u_yan  阅读(38)  评论(0编辑  收藏  举报