【BZOJ2662】冻结
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2662
又学到新技能了!!!
分层图最短路,一开始还以为是要建k+1个图,然后跑一遍最短路,其实没那么麻烦,我们在跑最短路的过程中就可以实现分层。
和往常一样,我们要用dist[u]+w去更新dist[v],但是为了分层,我们需要用dist[l][u]来存储最短路,表示从第0层第1个结点到第i层第u个结点的最短路,然后额外用dist[l][u]+w/2去更新dist[l+1][v],当然l+1<=k,因为我们最多进行k次操作。其实想象一下,也很好理解,相当于我们在把对哪些边使用魔法进行讨论,只不过保证无论用不用魔法,对哪些边用,都是在那种情况下的最短路,所以我们还需要求出min{dist[l][n]}作为答案。
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <queue> 5 6 using namespace std; 7 8 const int maxn = 55, maxm = 1e3 + 5, inf = 0x3f3f3f3f; 9 10 int head[maxn], eid; 11 12 struct Edge { 13 int v, w, next; 14 } edge[2 * maxm]; 15 16 inline void insert(int u, int v, int w) { 17 edge[++eid].v = v; 18 edge[eid].w = w; 19 edge[eid].next = head[u]; 20 head[u] = eid; 21 } 22 23 int k, dist[maxn][maxn], vis[maxn][maxn]; 24 25 struct node { 26 int level, id, dist; 27 node(int l, int i, int d) : level(l), id(i), dist(d) {} 28 bool operator < (const node& rhs) const { 29 return dist > rhs.dist; 30 } 31 }; 32 33 priority_queue<node> q; 34 35 inline void dijkstra() { 36 memset(dist, inf, sizeof(dist)); 37 dist[0][1] = 0; 38 q.push(node(0, 1, 0)); 39 while (!q.empty()) { 40 int l = q.top().level, u = q.top().id; 41 q.pop(); 42 if (vis[l][u]) continue; 43 vis[l][u] = 1; 44 for (int p = head[u]; p; p = edge[p].next) { 45 int v = edge[p].v, w = edge[p].w; 46 if (dist[l][v] > dist[l][u] + w) { 47 dist[l][v] = dist[l][u] + w; 48 q.push(node(l, v, dist[l][v])); 49 } 50 if (l + 1 <= k && dist[l + 1][v] > dist[l][u] + w / 2) { 51 dist[l + 1][v] = dist[l][u] + w / 2; 52 q.push(node(l + 1, v, dist[l + 1][v])); 53 } 54 } 55 } 56 } 57 58 int main() { 59 int n, m, ans = inf; 60 scanf("%d%d%d", &n, &m, &k); 61 for (int i = 1; i <= m; ++i) { 62 int a, b, t; 63 scanf("%d%d%d", &a, &b, &t); 64 insert(a, b, t); 65 insert(b, a, t); 66 } 67 dijkstra(); 68 for (int i = 0; i <= k; ++i) 69 ans = min(ans, dist[i][n]); 70 printf("%d", ans); 71 return 0; 72 }