AT4733 [ABC132E] Hopscotch Addict 题解
题目传送门
思路
分层图跑最短路。
\(∵\) 题目中说每次只能走 \(3\) 步, \(∴\) 我们可以把一条边拆成三条边,
拆成 \(1\) 到 \(2\),\(2\) 到 \(3\),\(3\) 到 \(2\) 的三条边权为 \(1\) 的边。
连边时,可以把边建在所有边的后面:
add (x, y + n) ;
add (x + n, y + n * 2) ;
add (x + n * 2, y) ;
然后跑一遍从 \(S\) 开始的最短路。
\(∵\) 因为每个点都跑了三遍,\(∴\) 最终答案 \(val_t \div 3\)。
其他题解跑最短路大多数用的是 Dijkstra
,我就用 SPFA
写吧。
代码如下:
#include <stdio.h>
#include <cstring>
#include <queue>
using namespace std;
const int N = 3e5 + 10; // 这里数组要开三倍,因为要连三条边。
const int INF = 0x3f3f3f3f;
void add (int, int) ;
void SPFA (int) ;
bool f[N];
int n, m;
int s, t;
int tot;
int val[N];
int now[N], pre[N], son[N];
queue <int> q;
main () {
scanf ("%d %d", &n, &m) ;
for (int x, y; m; -- m) {
scanf ("%d %d", &x, &y) ;
// 连三条边。
add (x, y + n) ;
add (x + n, y + n * 2) ;
add (x + n * 2, y) ;
}
scanf ("%d %d", &s, &t) ;
SPFA (s) ;
if (val[t] == INF)
puts ("-1") ;
else
printf ("%d", val[t] / 3) ; // 最终答案除以三。
}
void add (int x, int y) { // 建图。
pre[++ tot] = now[x];
son[tot] = y;
now[x] = tot;
}
void SPFA (int s) { // SPFA 求最短路。
memset (val, 0x3f, sizeof val) ;
val[s] = 0;
q.push (s) ;
for (; !q.empty () ;) {
int x = q.front () ;
q.pop () ;
f[x] = 1;
for (int i = now[x]; i; i = pre[i]) {
int y = son[i];
if (val[y] > val[x] + 1) {
val[y] = val[x] + 1;
if (!f[y]) {
f[y] = 1;
q.push (y) ;
}
}
}
}
}