HDU 1535 Invitation Cards 【反向建图最短路】

传送门
// 题意 : 给您一个(n, m) 的有向图, 问从1出发到达所有点的最小花费和所有点回到点1的最小花费和是多少.

// 思路: 从点1到所有点的最短距离肯定是要跑一遍单源最短路的, 问题是如何算所有点回到点1的最小花费和了? 暴力是肯定不行的. 我们可以发现如果一条边它是不能回到点1的, 那么它的存在对答案就没有意义的, 也就是我们直接对原图进行反向建边, 原来正向的是不会影响答案的, 因为不会再去走那条边了, 然后在从1开始跑一遍最短路, 就可以得到所有点到点1的最短路是多少了. 也就是反向建图和正向建图跑两遍最短路就可以得出答案了~

AC Code

const int maxn = 1e6+5;
int cnt[2], head[2][maxn];
struct node
{
    int to, next, w;
    bool operator < (const node& a) const {
        return w > a.w;
    }
} e[2][maxn];
void add(int u, int v,int w, int tag) {
    e[tag][cnt[tag]] = (node){v,head[tag][u],w};
    head[tag][u] = cnt[tag]++;
}
void init() {
    cnt[0] = cnt[1] = 0;
    Fill(head[0], -1);
    Fill(head[1], -1);
}
int n, m;
bool vis[maxn];
int dis[2][maxn];
void dij(int st,int ed, int tag)
{
    priority_queue q;
    Fill(dis[tag],inf); Fill(vis,0);
    dis[tag][st] = 0;
    q.push((node){st, 0, 0});
    while (!q.empty()) {
        node u = q.top();
        q.pop();
        if(vis[u.to]) continue;
        vis[u.to] = 1; 

        for (int i = head[tag][u.to]; ~i; i = e[tag][i].next) {
            node k = e[tag][i];
            if (dis[tag][k.to] > dis[tag][u.to] + k.w) {
                dis[tag][k.to] = dis[tag][u.to] + k.w;
                q.push((node){k.to, 0, dis[tag][k.to]});
            }
        }
    }
}
void solve() {
    init();
    scanf("%d%d",&n,&m);
    for (int i = 1 ; i<= m ; i ++) {
        int u, v, w;
        scanf("%d%d%d", &u, &v, &w);
        add(u, v, w, 0);
        add(v, u, w, 1);
    }
    dij(1, n, 0);
    dij(1, n, 1);
    ll ans = 0;
    for (int i = 1 ; i <= n ; i ++) {
        ans += dis[0][i] + dis[1][i];
    }
    printf("%lld\n", ans);
}

你可能感兴趣的:(最短路相关)