zoukankan      html  css  js  c++  java
  • [总结]关于反向建图

    今天做了这道题目.发现反向建图在某些情境下确实有各种特殊的效果.

    当然,既然提到反向,下面讨论的图都是有向图.

    1.求最短路:从单到多变为多到单

    上面提到的那道题目建立模型为:

      给出一张有向图并指定其中的一个节点x,要求计算出一个点,满足从该点到x节点的最短路长度与从x节点到该节点的最短路长度之和最大.

    利用Dijkstra(在这里可行的单源最短路算法)可以很容易算出从节点x到任意点的最短距离,现在需要求解从任意点到节点x的最短距离.

    利用反向建图:

      额外建立一个有向图,该图中所有的边都与原图方向相反,权值不变.

      在这张图中再次使用Dijkstra求出从节点x到任意点的最短距离.

      在这张图上得到的最短距离dist[i]就是在原图上从节点i到节点x的最短距离.

    参考:

    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <queue>
    using namespace std;
    
    struct E{
        int to, wei;
        bool operator<(const E &other) const {return wei > other.wei;}
    };
    vector<E> e1[1010], e2[1010];
    priority_queue<E> q;
    int n, m, x, dist1[1010], dist2[1010];
    
    int main(){
        scanf("%d%d%d", &n, &m, &x);
        while(m--){
            int a, b, t;
            scanf("%d%d%d", &a, &b, &t);
            e1[a].push_back({b, t});
            e2[b].push_back({a, t});
        }
    
        // from x to home
        memset(dist1, -1, sizeof(dist1));
        q.push({x, 0});
        while(!q.empty()){
            E cur = q.top();
            q.pop();
            if(dist1[cur.to] != -1) continue;
    
            dist1[cur.to] = cur.wei;
            for(int i = 0; i < e1[cur.to].size(); i++)
                q.push({e1[cur.to][i].to, e1[cur.to][i].wei + cur.wei});
        }
    
        // from home to x
        memset(dist2, -1, sizeof(dist2));
        q.push({x, 0});
        while(!q.empty()){
            E cur = q.top();
            q.pop();
            if(dist2[cur.to] != -1) continue;
    
            dist2[cur.to] = cur.wei;
            for(int i = 0; i < e2[cur.to].size(); i++)
                q.push({e2[cur.to][i].to, e2[cur.to][i].wei + cur.wei});
        }
    
        int ans = 0;
        for(int i = 1; i <= n; i++)
            ans = max(ans, dist1[i] + dist2[i]);
    
        printf("%d
    ", ans);
    
        return 0;
    }
    Silver Cow Party

    2.正难则反

    这是一个看起来比较宽泛的应用,举个例子.

    P3916 图的遍历

    给出一个有向图,求出每一个节点从自己出发能到达的编号最大的节点.数据达到了1e5.

    如果让每个节点独立地找太慢了,反过来,让编号最大的节点去找能遍历到它的节点.

    反向建图,从编号最大的N号节点开始,依次对N,N-1,N-2...号节点执行如下操作:

      遍历其子节点,对所有未标记的节点标上其编号并(递归地)遍历该节点的子节点.

    参考:

    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <vector>
    using namespace std;
    
    int n, m;
    vector<int> s[100010];
    int ans[100010];
    
    void dfs(int x, int k) {
        if (ans[x]) return;
        ans[x] = k;
        for(auto i: s[x]) dfs(i, k);
    }
    
    int main() {
        cin >> n >> m;
        while(m--) {
            int x, y;
            cin >> x >> y;
            s[y].push_back(x);
        }
    
        for (int i = n; i >= 1; i--) dfs(i, i);
        for (int i = 1; i <= n; i++) cout << ans[i] << ' ';
    
        return 0;
    }
    P3916

    先记下这么多.

  • 相关阅读:
    高精度 模板
    《图论》邻接表
    模板整理
    H
    C
    同余定理的应用(处理大数
    H
    1153: 简易版最长序列
    1152: 二分搜索
    1151: 大整数加法(正数)
  • 原文地址:https://www.cnblogs.com/Gaomez/p/14613683.html
Copyright © 2011-2022 走看看