P4822 [BJWC2012]冻结(分层图最短路)
题目描述:
我们考虑最简单的旅行问题吧: 现在这个大陆上有 NN 个城市,MM 条双向的道路。城市编号为 11 ~ NN,我们在 11 号城市,需要到 NN 号城市,怎样才能最快地到达呢?
这不就是最短路问题吗?我们都知道可以用 Dijkstra、Bellman-Ford、Floyd-Warshall等算法来解决。
现在,我们一共有 KK 张可以使时间变慢 50%的 SpellCard,也就是说,在通过某条路径时,我们可以选择使用一张卡片,这样,我们通过这一条道路的时间 就可以减少到原先的一半。需要注意的是:
- 在一条道路上最多只能使用一张 SpellCard。
- 使用一张SpellCard 只在一条道路上起作用。
- 你不必使用完所有的 SpellCard。
给定以上的信息,你的任务是:求出在可以使用这不超过 KK 张时间减速的 SpellCard 之情形下,从城市 11 到城市 NN 最少需要多长时间。
思路分层图最短路
AC代码:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 10000005; const int inf = 0x3f3f3f3f; struct edge { int f, t, w, nxt; }e[maxn * 2]; int hd[maxn], tot; void add(int f, int t, int w) { e[++tot] = { f,t,w,hd[f] }; hd[f] = tot; } int dis[maxn]; bool vis[maxn]; struct node { int dis, id; bool operator<(node b)const { return dis > b.dis; } }; void dj(int s) { memset(dis, 0x3f, sizeof(dis)); memset(vis, 0, sizeof(vis)); priority_queue<node>q; dis[s] = 0; q.push({ 0,s }); while (!q.empty()) { node t = q.top(); q.pop(); if (vis[t.id])continue; vis[t.id] = 1; int u = t.id; for (int i = hd[u]; i; i = e[i].nxt) { int v = e[i].t; if (vis[v])continue; if (dis[u] + e[i].w < dis[v]) { dis[v] = dis[u] + e[i].w; q.push({ dis[v], v }); } } } } int n, m, k; int s, t; int main() { //freopen("test.txt", "r", stdin); scanf("%d%d%d", &n, &m, &k); for (int i = 1; i <= m; i++) { int a, b, w; scanf("%d%d%d", &a, &b, &w); for (int j = 0; j <= k; j++) {//为每一层建图 add(j*n+a, j*n+b, w); add(j*n+b, j*n+a, w); if (j > 0) {//两层之间连单向边 add((j - 1) * n + a, j * n + b, w >> 1); add((j - 1) * n + b, j * n + a, w >> 1); } } } int ans = inf; dj(1); for (int i = 0; i <= k; i++) {//每一层到终点的最小值 ans = min(ans, dis[i * n + n]); } printf("%d",ans); return 0; }