HDU - 6582 Path

问题是确定断开最短的边使得从1到n最短路长度增加
转化成两个问题:

  • 确定边在最短路上
  • 确定断开最短路上的那一条边

对于第一个问题,如果边(u,v)在最短路上则dis(1,u) + cost(u,v) + dis(v,n) = dis(1,n)
dis(a,b)代表从a到b的最短距离
其中,dis(1,u)可以直接从1开始跑dij,dis(v,n)可以从n开始反向建图之后dij

对于第二个问题,如果我们用从1到n最短路上的边建图G后,
问题就转化为在该图上求最小花费使得1与n不连通,即最小割
可以反向理解下,如果割掉一条边之后(1,n)仍然在G图上联通那么1到n的最短路长度必然不变,
反之割边后不连通则在原来的图中要么(1,n)不连通,要么最短路增大,因为断开的(u,v)是最短路上的边...
如果wa了注意开ll

#include <bits/stdc++.h>

#define int long long
using namespace std;
const int mod = 0x3f3f3f3f3f3f3f;
const int maxn = 2e4 + 7;
int t, n, m, u, v, val;

struct Edg {
    int u, v, val;//起点,终点,消耗
};

struct edg {
    int v, val;//到达点,消耗
} edges[maxn];

bool operator<(const edg &a, const edg &b) {
    return a.val > b.val;
}

vector<Edg> vg;
vector<edg> mp[2][maxn];//0正向,1反向
int dis[2][maxn];


void dij(int st, int op) {
    priority_queue<edg> que;
    que.push({st, 0});
    dis[op][st] = 0;
    while (que.size()) {
        edg now = que.top();
        que.pop();
        if (dis[op][now.v] < now.val)
            continue;
        for (auto to:mp[op][now.v]) {
            if (dis[op][to.v] > dis[op][now.v] + to.val) {
                dis[op][to.v] = dis[op][now.v] + to.val;
                que.push({to.v, dis[op][to.v]});
            }
        }
    }
}

struct Dinic {
    struct edge {
        int to, cap, rev;

        edge(int a, int b, int c) { to = a, cap = b, rev = c; }
    };

    vector<edge> G[maxn];
    int level[maxn];
    int iter[maxn];

    void init(int n) {
        memset(level, 0, sizeof level);
        memset(iter, 0, sizeof iter);
        for (int i = 0; i <= n; i++)
            G[i].clear();
    }

    void add(int from, int to, int cap) {
        G[from].push_back(edge(to, cap, G[to].size()));
        G[to].push_back(edge(from, 0, G[from].size() - 1));
    }

    void bfs(int s) {
        memset(level, -1, sizeof level);
        queue<int> que;
        level[s] = 0;
        que.push(s);
        while (que.size()) {
            int v = que.front();
            que.pop();
            for (int i = 0; i < G[v].size(); i++) {
                edge &e = G[v][i];
                if (e.cap > 0 && level[e.to] < 0)
                    level[e.to] = level[v] + 1, que.push(e.to);
            }
        }
    }

    int dfs(int v, int t, int f) {
        if (v == t)
            return f;
        for (int &i = iter[v]; i < G[v].size(); i++) {
            edge &e = G[v][i];
            if (e.cap > 0 && level[v] < level[e.to]) {
                int d = dfs(e.to, t, min(f, e.cap));
                if (d > 0) {
                    e.cap -= d, G[e.to][e.rev].cap += d;
                    return d;
                }
            }
        }
        return 0;
    }

    int run(int s, int t) {
        int flow = 0;
        while (1) {
            bfs(s);
            if (level[t] < 0)
                return flow;
            memset(iter, 0, sizeof iter);
            int f;
            while ((f = dfs(s, t, mod)) > 0)
                flow += f;
        }
    }
} F;

void init() {
    vg.clear(), F.init(n + 1);
    for (int i = 0; i <= n; ++i)
        dis[0][i] = dis[1][i] = mod,
                mp[0][i].clear(), mp[1][i].clear();
}


signed main() {
    cin >> t;
    while (t--) {
        cin >> n >> m;
        init();
        for (int i = 1; i <= m; i++) {
            cin >> u >> v >> val;
            vg.push_back({u, v, val});
            mp[0][u].push_back({v, val});
            mp[1][v].push_back({u, val});
        }
        dij(1, 0);
        dij(n, 1);
        for (auto eg:vg)
            if (dis[0][eg.u] + eg.val + dis[1][eg.v] == dis[0][n])
                F.add(eg.u, eg.v, eg.val);
        cout << F.run(1, n) << endl;
    }
}
posted @ 2021-03-16 21:38  naymi  阅读(48)  评论(0)    收藏  举报