• Path(最小割,最短路图)


    题意

    给定一个(n)个点,(m)条边的有向图,每个边有边权(w_i)

    需要删除一些边使得(1)(n)的最短路变长,求删除边的边权总和最小为多少。

    数据范围

    (1 leq T leq 10)

    (1 leq n, m leq 10000)

    (1 leq w_i leq 10^9)

    思路

    删去的这些边,肯定是最短路上的边。因此可以建立最短路图。

    最短路图的建立方式是,先求(1)到其他点的最短距离(dist1),然后建反图,求(n)到其他点的最短距离(dist2)。然后枚举每条边((u, v, w)),若(dist1[u] + dist2[v] + w = dist1[n]),则这条边就留下。

    建立完最短路图后,在最短路图上求最小割,即为答案。

    代码

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    
    using namespace std;
    
    typedef long long ll;
    typedef pair<ll, int> pli;
    
    const int N = 10010, M = 2 * N;
    const ll inf = 1e18;
    
    int n, m, S, T;
    int h[N], e[M], ne[M], w[M], idx;
    ll f[M];
    int cur[N], d[N];
    ll dist1[N], dist2[N];
    bool st[N];
    
    struct Edge
    {
        int a, b, c;
    }edge[M];
    
    void add1(int a, int b, int c)
    {
        e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++;
    }
    
    void add2(int a, int b, ll c)
    {
        e[idx] = b, f[idx] = c, ne[idx] = h[a], h[a] = idx ++;
        e[idx] = a, f[idx] = 0, ne[idx] = h[b], h[b] = idx ++;
    }
    
    void dijkstra(int s, ll dist[])
    {
        for(int i = 1; i <= n; i ++) dist[i] = inf;
        for(int i = 1; i <= n; i ++) st[i] = false;
        priority_queue<pli, vector<pli>, greater<pli> > heap;
        heap.push({0, s});
        dist[s] = 0;
        while(heap.size()) {
            auto t = heap.top();
            heap.pop();
            int ver = t.second;
            ll distance = t.first;
            if(st[ver]) continue;
            st[ver] = true;
            for(int i = h[ver]; ~i; i = ne[i]) {
                int j = e[i];
                if(dist[j] > distance + (ll)w[i]) {
                    dist[j] = distance + (ll)w[i];
                    heap.push({dist[j], j});
                }
            }
        }
    }
    
    bool bfs()
    {
        memset(d, -1, sizeof(d));
        queue<int> que;
        que.push(S);
        d[S] = 0, cur[S] = h[S];
        while(que.size()) {
            int t = que.front();
            que.pop();
            for(int i = h[t]; ~i; i = ne[i]) {
                int ver = e[i];
                if(d[ver] == -1 && f[i]) {
                    d[ver] = d[t] + 1;
                    cur[ver] = h[ver];
                    if(ver == T) return true;
                    que.push(ver);
                }
            }
        }
        return false;
    }
    
    ll find(int u, ll limit)
    {
        if(u == T) return limit;
        ll flow = 0;
        for(int i = cur[u]; ~i && limit > flow; i = ne[i]) {
            cur[u] = i;
            int ver = e[i];
            if(d[ver] == d[u] + 1 && f[i]) {
                ll t = find(ver, min(f[i], limit - flow));
                if(!t) d[ver] = -1;
                f[i] -= t, f[i ^ 1] += t, flow += t;
            }
        }
        return flow;
    }
    
    ll dinic()
    {
        ll res = 0, flow;
        while(bfs()) {
            while(flow = find(S, inf)) {
                res += flow;
            }
        }
        return res;
    }
    
    int main()
    {
        int TT;
        scanf("%d", &TT);
        while(TT --) {
            scanf("%d%d", &n, &m);
            for(int i = 1; i <= n; i ++) h[i] = -1;
            idx = 0;
            for(int i = 0; i < m; i ++) {
                int a, b, c;
                scanf("%d%d%d", &a, &b, &c);
                add1(a, b, c);
                edge[i] = {a, b, c};
            }
            dijkstra(1, dist1);
            for(int i = 1; i <= n; i ++) h[i] = -1;
            idx = 0;
            for(int i = 0; i < m; i ++) {
                int a = edge[i].a, b = edge[i].b, c = edge[i].c;
                add1(b, a, c);
            }
            dijkstra(n, dist2);
            for(int i = 1; i <= n; i ++) h[i] = -1;
            idx = 0;
            S = 1, T = n;
            for(int i = 0; i < m; i ++) {
                int a = edge[i].a, b = edge[i].b, c = edge[i].c;
                if(dist1[a] + dist2[b] + (ll)c == dist1[n]) {
                    add2(a, b, (ll)c);
                }
            }
            printf("%lld
    ", dinic());
        }
        return 0;
    }
    
  • 相关阅读:
    使用FormData,进行Ajax请求并上传文件
    oracle视图详解
    Unicode和UTF-8之间的关系
    如何访问tomcat所在服务器的其他盘符的资源。
    React首次渲染过程
    react知识点总结
    WebSocket基础
    gulp 批量添加类名 在一个任务中使用多个文件来源
    Chrome浏览器取消INPUT自动记忆下拉框
    Angular7 Drag and Drop
  • 原文地址:https://www.cnblogs.com/miraclepbc/p/14390748.html
Copyright © 2020-2023  润新知