[TJOI2019]大中锋的游乐场 题解
题目描述
一个人在一个无向图内,点权为 \(1\) 或 \(-1\),求在任意时刻下,经过点权和绝对值不超过 \(k\) 的最短路。
\(1≤n≤10^4,1 \leq m\leq 10^5,1 \leq k\leq 10\)
想法
根据数据范围中 \(1\leq k \leq 10\) 不难想到这是一道分层图题。
思路
分层的依据就照着题目设好了:以经过点权和为 \(j(-k\leq j\leq k)\) 进行分层即可。
对于边,我们进行如下操作:
- 一条边 \((u, v, w)\),其中 \(u\) 在 \(i\) 层,\(v\) 在 \(i + type[v]\) 层,连接一条 \(u\) 到 \(v\),权重为 \(w\) 的边。
\(type[v]\) 表示 \(v\) 的点权。
- 注意由于到达一个点就一定会改变点权和,因此对于这道题而言没有层间的边。
实现
为了方便这题我用逻辑建图的方法,不实际把图建起来,而是在进行算法过程的时候有条件地考虑可行点。
-
数组下标不能是负数,所以把所有的表示层数的 \(j\) 加上 \(k\),这样 \(j\) 的取值范围就变为了: \(0\leq j\leq 2k\),方便很多。
-
Trick: 由于第一个点也需要考虑,所以干脆直接从 \(0\) 连了一条向起点 \(S\) 的 \(0\) 边,最短路的起点就设成 \(0\),这样省去了分类讨论。
// Problem: P5340 [TJOI2019]大中锋的游乐场
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P5340
// Memory Limit: 125 MB
// Time Limit: 1000 ms
// Author: Moyou
// Copyright (c) 2022 Moyou All rights reserved.
// Date: 2022-12-14 20:20:58
vector<PII> g[N];
int n, m, k, a[N];
int S, T;
bool st[N][15];
int dist[N][15];
void add(int a, int b, int c)
{
g[a].push_back({b, c});
}
struct qwq
{
int id, type, d;
bool operator<(const qwq &D) const
{
return d > D.d;
}
};
void init()
{
cin >> n >> m >> k;
for (int i = 1; i <= n; i++)
g[i].clear();
for (int i = 1; i <= n; i++)
{
cin >> a[i];
if (a[i] == 2)
a[i] = -1;
}
memset(st, 0, sizeof st);
memset(dist, 0x3f, sizeof dist);
for (int i = 1; i <= m; i++)
{
int a, b, c;
cin >> a >> b >> c;
add(a, b, c), add(b, a, c);
}
cin >> S >> T;
add(0, S, 0);
}
int dijkstra()
{
priority_queue<qwq> heap;
heap.push({0, k, 0});
dist[0][k] = 0;
while (heap.size())
{
auto t = heap.top();
heap.pop();
int u = t.id, ty = t.type;
if (st[t.id][t.type])
continue;
st[u][ty] = 1;
for (auto i : g[u])
{
int w = i.y, j = i.x;
if (a[j] + ty <= 2 * k && a[j] + ty >= 0 && dist[j][a[j] + ty] > dist[u][ty] + w)
{
dist[j][a[j] + ty] = dist[u][ty] + w;
heap.push({j, a[j] + ty, dist[j][a[j] + ty]});
}
}
}
int ans = INF;
for (int i = 0; i <= 2 * k; i++) // 取最小答案
{
ans = min(ans, dist[T][i]);
}
return (ans == INF ? -1 : ans);
}
int main()
{
int T;
cin >> T;
while (T--)
{
init();
cout << dijkstra() << endl;
}
return 0;
}