HDU-4479 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; }