Escape
#图论 #最短路 #分层图
题目描述
Sneaker wakes up in a vast maze, and now he wants to escape from it. Through the map found in every room of the maze, Sneaker learns the structure of the maze. The maze consists of n n n rooms, with Sneaker starting in room 1 1 1, and the exit is in room n n n. Additionally, there are m m m two-way passages in the maze, each connecting two different rooms, and the two directions of each passage are isolated from each other. It is guaranteed that no two different passages connect the same pair of rooms, and there is no passage that connects a room to itself. Moreover, it is guaranteed that any two rooms can be reached from each other through a series of passages. Sneaker also discovers that there are k k k slayer robots in the maze. The i i i-th slayer robot initially stays in room s i s_i si. Obviously, Sneaker does not want and cannot encounter these slayer robots. If Sneaker starts moving, each slayer robot will move simultaneously. Specifically, Sneaker will choose a passage connected to the room he is currently in and move to the room on the other side of the passage. At the same time, each slayer robot will randomly choose a passage connected to the room it is in and move to the room on the other side of the passage. Every slayer robot will enter and exit the passage at the same time as Sneaker. All slayer robots will record the passages they pass through. If a slayer robot travels through a passage that is the same as the last recorded passage, it can choose to erase both occurrences of this passage from its record. In other words, the slayer robot can choose to undo a record. For example, if a slayer robot currently has a record of passages ( 1 , 2 ) , ( 2 , 7 ) , ( 7 , 3 ) (1,2), (2,7), (7,3) (1,2),(2,7),(7,3) and is now in room 3 3 3, it can choose to move through a new passage, say ( 3 , 6 ) (3,6) (3,6), and its record will become ( 1 , 2 ) , ( 2 , 7 ) , ( 7 , 3 ) , ( 3 , 6 ) (1,2), (2,7), (7,3), (3,6) (1,2),(2,7),(7,3),(3,6), with the robot ending up in room 6 6 6. Alternatively, it can move through passage ( 3 , 7 ) (3,7) (3,7) to return to room 7 7 7, and its record will become ( 1 , 2 ) , ( 2 , 7 ) (1,2), (2,7) (1,2),(2,7). Furthermore, if the slayer robot then chooses to move through a passage back to room 2 2 2, its record will become ( 1 , 2 ) (1,2) (1,2). However, if it moves from room 3 3 3 directly to room 2 2 2, its record cannot become ( 1 , 2 ) (1,2) (1,2); instead, it will become ( 1 , 2 ) , ( 2 , 7 ) , ( 7 , 3 ) , ( 3 , 2 ) (1,2), (2,7), (7,3), (3,2) (1,2),(2,7),(7,3),(3,2). Additionally, all slayer robots share a same self-destruct parameter d d d. If a slayer robot arrives in a room and finds that its record of passages exceeds d d d, it will immediately self-destruct. If Sneaker enters a room and finds that a slayer robot is in the process of self-destructing or has already self-destructed, it is not considered an encounter with the robot. Now, Sneaker wants to plan a route with the minimum number of passages and ensure that he will not encounter any slayer robot. Can you help him? Note: If Sneaker is moving from room x x x to room y y y through a passage, and a slayer robot is moving in the opposite direction, from room y y y to room x x x through the same passage, Sneaker will not encounter the slayer robot because the two directions of the passage are isolated from each other. The sneaker only knows the initial position of each slayer robot, but does not know their positions at every moment. If both a slayer robot and Sneaker arrive at room n n n at the same time, then Sneaker is considered to have encountered the slayer robot and cannot escape from the maze.
输入格式
The first line contains an integer T T T ( 1 ≤ T ≤ 1 0 5 ) (1 \leq T \leq 10^5) (1≤T≤105), representing the number of test cases. For each test case, the first line contains three integers n n n, m m m, and d d d ( 2 ≤ n ≤ 2 × 1 0 5 (2 \leq n \leq 2 \times 10^5 (2≤n≤2×105, n − 1 ≤ m ≤ min { 5 × 1 0 5 , n ( n − 1 ) 2 } n-1 \leq m \leq \min\{5 \times 10^5, \frac{n(n-1)}{2}\} n−1≤m≤min{5×105,2n(n−1)}, 1 ≤ d < n ) 1 \leq d < n) 1≤d<n), which represent the number of rooms in the maze, the number of passages, and the self-destruct parameter, respectively. The next m m m lines each contain two integers x i x_i xi and y i y_i yi ( 1 ≤ x i < y i ≤ n ) (1 \leq x_i < y_i \leq n) (1≤xi<yi≤n), indicating that the i i i-th passage connects room x i x_i xi and room y i y_i yi. It is guaranteed that for any i ≠ j i \neq j i=j, x i ≠ x j x_i \neq x_j xi=xj or y i ≠ y j y_i \neq y_j yi=yj. It is guaranteed that any two rooms can be reached from each other through a series of passages. The ( m + 2 ) (m + 2) (m+2)-th line contains several integers. The first integer k k k ( 0 ≤ k ≤ n − 2 ) (0\leq k\leq n-2) (0≤k≤n−2) represents the number of slayer robots, followed by k k k integers s 1 , s 2 , … , s k s_1, s_2, \dots, s_k s1,s2,…,sk ( 2 ≤ s i < n ) (2\leq s_i<n) (2≤si<n) which represent the initial room where each slayer robot is. It is guaranteed that the sum of n n n over all test cases does not exceed 5 × 1 0 5 5 \times 10^5 5×105, and the sum of m m m over all test cases does not exceed 2 × 1 0 6 2 \times 10^6 2×106.
输出格式
For each test case, if there exists a valid route, output a single integer p p p in the first line, representing the minimum number of passages in the valid route. In the second line, output p + 1 p+1 p+1 integers z 0 = 1 , z 1 , … , z p = n z_0=1, z_1, \dots, z_p=n z0=1,z1,…,zp=n, representing the sequence of rooms that the route passes through. If no valid route exists, output a single integer − 1 -1 −1.
样例 #1
样例输入 #1
2
7 8 2
1 2
2 3
3 7
2 5
5 6
3 6
1 4
4 5
1 4
7 8 2
1 2
2 3
3 7
2 5
5 6
3 6
1 4
4 5
1 5
样例输出 #1
3
1 2 3 7
-1
解法
解题思路
首先杀手机器人一定不会因为超过 d d d而自爆,而是小于 d d d的地方一直徘徊,因此我们可以对机器人可以到达的位置进行标记,求出机器人到达位置的最小时间。
因为机器人到达一个点之后,可以在附近一个点反复横跳,因此在任意大于最小到达时间的奇数(或偶数)时间内,都能到达这个点。
不过,由于这个图是存在环的,有时一个点可以被多次到达,那么我们应该更新它的最小奇时间和最小偶时间。
如下图所示,从 3 3 3号点开始,到达 2 2 2号点的最小奇时间是 1 1 1,最小偶时间是 4 4 4
因此我们对整张图分层,分为奇偶两张图,两张图之间相邻的点存在边,也就是上图中从偶图中 3 3 3号点连接奇图中的 2 2 2号的,奇图的 2 2 2号点连接偶图的 1 , 5 1,5 1,5点,以此类推。
最后我们对机器人跑一遍多源最短路径 b f s bfs bfs,然后再跑一遍从出发点开始的 b f s bfs bfs,同样是跑分层图,判断能否在机器人到之前抢先来到这个点,或这个点机器人无法到达。
对于路径的输出,只需要记录当前节点的前驱节点,然后在终点倒推这个路径即可。
代码
void solve() {
int n, m, d;
std::cin >> n >> m >> d;
std::vector<std::vector<int>>e(n + 1);
for (int i = 1; i <= m; ++i) {
int u, v;
std::cin >> u >> v;
e[u].emplace_back(v);
e[v].emplace_back(u);
}
int k;
std::cin >> k;
std::vector<int>a(k + 1);
for (int i = 1; i <= k; ++i) {
std::cin >> a[i];
}
std::vector<std::array<int, 2>>dis1(n + 1, {INF,INF}), vis1(n + 1);
auto bfs1 = [&]() ->void {
std::queue<pii>q;
for (int i = 1; i <= k; ++i) {
q.push({ a[i],0 });
vis1[a[i]][0] = 1;
dis1[a[i]][0] = 0;
}
while (q.size()) {
auto [u, len] = q.front(); q.pop();
for (auto& v : e[u]) {
if (vis1[v][len ^ 1] || dis1[u][len] + 1 > d) continue;
dis1[v][len ^ 1] = dis1[u][len] + 1;
vis1[v][len ^ 1] = 1;
q.push({ v,len ^ 1 });
}
}
};
bfs1();
std::vector<std::array<int, 2>>dis2(n + 1, { INF,INF }), vis2(n + 1), pre(n + 1);
auto bfs2 = [&]() {
std::queue<pii>q;
q.push({ 1,0 });
vis2[1][0] = 1; dis2[1][0] = 0;
while (q.size()) {
auto [u, len] = q.front(); q.pop();
for (auto& v : e[u]) {
if (vis2[v][len ^ 1] || dis2[u][len] + 1 >= dis1[v][len ^ 1]){
continue;
}
dis2[v][len ^ 1] = dis2[u][len] + 1;
vis2[v][len ^ 1] = 1;
q.push({ v,len ^ 1 });
pre[v][len ^ 1] = u;
}
}
};
bfs2();
if (!vis2[n][0] && !vis2[n][1]) {
std::cout << -1 << "\n";
return;
}
int res = INF, p = 0;
for (int i = 0; i <= 1; ++i) {
if (vis2[n][i] && dis2[n][i] < res) {
res = dis2[n][i];
p = i;
}
}
std::cout << res << "\n";
std::vector<int>path;
path.emplace_back(n);
int now = n;
while (path.size() < res + 1) {
now = pre[now][p];
p = p ^ 1;
path.emplace_back(now);
}
for (auto it = path.rbegin(); it != path.rend(); ++it) {
std::cout << *it << " ";
}
std::cout << "\n";
}
signed main() {
std::ios::sync_with_stdio(0);
std::cin.tie(0);
std::cout.tie(0);
int t = 1;
std::cin >> t;
while (t--) {
solve();
}
};