思路:
一开始以为所有的点所在的层都不同,就一直wa,后面改成存每一层的点,再算每一层的点与上下两层点的距离,结果显然会超时,看了题解后才了解了一个神奇的建图方法可以大大降低算法复杂度。
建图思路:
对于每一层可以抽象为一个点,为了避免与给出点冲突第 i 层抽象为为第 i+n 点,每一层到达本层点的距离都是 0,层中每个点到达上一层点或下一层点的距离都为 c,这样就可以通过虚拟出来的层点实现每个点 i 到达上或下一层任一的点的操作,然后再将额外边加入,跑一遍堆优化的dijkstra即可
代码:
#include <bits/stdc++.h>
#define fastio ios::sync_with_stdio(false), cin.tie(NULL), cout.tie(NULL)
#define debug(a) cout << "debug : " << (#a) << " = " << a << endl
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 1e5 + 10;
const int INF = 0x3f3f3f3f;
const double eps = 1e-3;
const int mod = 998244353;
int n, m, c;
vector<PII> a[N * 2];
int dis[N * 2], ceng[N]; //ceng[i]记录i点是哪一层
bool vis[N * 2];
int dijkstra()
{
memset(vis, false, sizeof vis);
memset(dis, INF, sizeof dis);
priority_queue<PII, vector<PII>, greater<PII>> pq;
pq.push({0, 1});
dis[1] = 0;
while (pq.size())
{
PII t = pq.top();
pq.pop();
int idx = t.second, distance = t.first;
if (vis[idx])
continue;
vis[idx] = true;
for (int i = 0; i < a[idx].size(); i++)
{
PII p = a[idx][i];
int j = p.second, w = p.first;
if (dis[j] > w + distance)
{
dis[j] = w + distance;
pq.push({dis[j], j});
}
}
}
if (dis[n] == INF)
return -1;
else
return dis[n];
}
int main()
{
fastio;
int T;
cin >> T;
for (int j = 1; j <= T; j++)
{
cin >> n >> m >> c;
for (int i = 1; i <= n; i++)
cin >> ceng[i];
for (int i = 1; i <= n; i++)
{
a[ceng[i] + n].push_back({0, i}); //i点所在层到i点的距离为0
if (ceng[i] == 1) //当在第一层时只有与下面一层
a[i].push_back({c, ceng[i] + n + 1}); //i点到下一层距离为c
else if (ceng[i] == n) //当在最后一层时只有上面一层
a[i].push_back({c, ceng[i] + n - 1}); //i点到上面一层距离也为c
else //在中间层次,上下都可去
{
a[i].push_back({c, ceng[i] + n + 1});
a[i].push_back({c, ceng[i] + n - 1});
}
}
for (int i = 1; i <= m; i++)
{
int l, r, w;
cin >> l >> r >> w;
a[l].push_back({w, r}), a[r].push_back({w, l});
}
cout << "Case #" << j << ": " << dijkstra() << endl;
for (int i = 1; i <= 2 * n; i++)
a[i].clear();
}
return 0;
}