HDU4479 Shortest path 边权递增最短路

题意:给定一个图,求从1到N的递增边权的最短路。

解法:类似于bellman-ford思想,将所有的边先按照权值排一个序,然后依次将边加入进去更新,每条边只更新一次,为了保证得到的路径是边权递增的,每次将相同权值的边全部取出来一同更新,每条边能够更新的前提是某一个端点在之前被更小的边权更新过。另外一个要注意的地方就是一次相同边的更新中,要把所有的更新暂存起来最后一起去更新,这样是为了防止同一权值的边被多次加入到路径中去。

代码如下:

#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
using namespace std;

typedef long long LL;
int N, M;

struct Edge {
    int x, y, d;
    bool operator < (const Edge & ot) const {
        return d < ot.d;
    }
}e[50005];

const LL INF = 0x3f3f3f3f3f3f3f3fLL;
LL   dis[10005];

struct Rec {
    int v;
    LL d;
}rec[10005];

void update(int l, int r) {
    int u, v, d, idx = 0;
    for (int i = l; i <= r; ++i) {
        u = e[i].x, v = e[i].y, d = e[i].d;
        if (dis[u] != INF && dis[v] > dis[u] + d) {
            rec[idx].v = v, rec[idx++].d = dis[u] + d;
        }
        if (dis[v] != INF && dis[u] > dis[v] + d) {
            rec[idx].v = u, rec[idx++].d = dis[v] + d;
        }
    }
    for (int i = 0; i < idx; ++i) {
        dis[rec[i].v] = min(dis[rec[i].v], rec[i].d);
    }
}

void solve() {
    memset(dis, 0x3f, sizeof (dis));
    dis[1] = 0;
    for (int i = 0, j; i < M; i = j) {
        for (j = i + 1; j < M; ++j) {
            if (e[j].d != e[i].d) break;
        }
        update(i, j-1); // 将权值相等个边取出来
    }
    if (dis[N] == INF) puts("No answer");
    else printf("%I64d\n", dis[N]);
}

int main() {
    int T;
    scanf("%d", &T);
    while (T--) {
        scanf("%d %d", &N, &M);
        for (int i = 0; i < M; ++i) {
            scanf("%d %d %d", &e[i].x, &e[i].y, &e[i].d);
        }
        sort(e, e + M);
        solve();
    }
    return 0;
}
原文地址:https://www.cnblogs.com/Lyush/p/3127371.html