知识点:BFS,状态压缩
这个题首先一眼就是BFS,并且还要打印路径,然后就是最重要的问题,状态,首先直观的感觉,状态可以用三进制来表示,3的15次方一定能涵盖所有的情况,因为每个位置有三种可能,但是经过思考发现,只有一个机器人,那么我们把机器人提出来,用二进制来表示,某个位置是石头还是空格,然后再加一维,来表示机器人的位置,这样就行了,BFS的时候所有的石头都尝试移动,机器人也尝试移动,这样就能暴力的遍历所有的情况了,做到不漏,最后得到就是最少步数,输出的时候需要注意,起点不是到了机器人的起点,而是二进制数,以及机器人位置,共同组成的,二元组,到了这个的初始位置才是真的到了起点,倒序输出就行了
一开始不会三进制状态压缩,然后就想着用两个二进制数来表示状态,理论上应该是可行的,但是实际不行,空间啥的应该不行,这个题还真亏了读题,发现只有一个机器人,这个是做题的关键,但是一开始写的时候没有特判,输出-1,改了就过了,这个题写了1个小时,
#include <bits/stdc++.h>
using namespace std;
const int N = 16;
const int M = 500;
struct state {
int u, v;
state() {}
state(int a, int b): u(a), v(b) {}
} pre[(1 << N) + 5][N];
int n, m, s, e, start, dist[(1 << N) + 5][N], Case;
int tot, head[N], ver[M], nxt[M];
void add(int x, int y) {
ver[++tot] = y;
nxt[tot] = head[x]; head[x] = tot;
}
void bfs() {
for (int i = 0; i < (1 << (n + 1)); i++) {
for (int j = 1; j <= n; j++) dist[i][j] = -1;
}
queue<state> q;
q.push(state(start, s));
dist[start][s] = 0;
while (!q.empty()) {
state now = q.front(); q.pop();
if (now.v == e) {
int ans = dist[now.u][now.v];
vector<state> vec;
while (true) {
state cur = pre[now.u][now.v];
if (cur.v != now.v) {
vec.push_back(state(cur.v, now.v));
} else {
int to, from;
for (int i = 1; i <= n; i++) {
int x1 = (cur.u >> i) & 1;
int x2 = (now.u >> i) & 1;
if (x1 && !x2) to = i;
if (!x1 && x2) from = i;
}
vec.push_back(state(to, from));
}
now = cur;
if (now.u == start && now.v == s) break;
}
reverse(vec.begin(), vec.end());
printf("Case %d: %d\n", ++Case, ans);
for (int i = 0; i < (int) vec.size(); i++) {
printf("%d %d\n", vec[i].u, vec[i].v);
}
printf("\n");
return;
}
for (int i = 1; i <= n; i++) {
if (!((now.u >> i) & 1) && now.v != i) continue;
if (((now.u >> i) & 1)) {
for (int j = head[i]; j; j = nxt[j]) {
int y = ver[j];
if (!((now.u >> y) & 1) && now.v != y) {
int cur = now.u;
cur &= (~(1 << i));
cur |= (1 << y);
if (dist[cur][now.v] == -1) {
q.push(state(cur, now.v));
pre[cur][now.v] = now;
dist[cur][now.v] = dist[now.u][now.v] + 1;
}
}
}
} else {
for (int j = head[i]; j; j = nxt[j]) {
int y = ver[j];
if (!((now.u >> y) & 1)) {
if (dist[now.u][y] == -1) {
q.push(state(now.u, y));
pre[now.u][y] = now;
dist[now.u][y] = dist[now.u][now.v] + 1;
}
}
}
}
}
}
printf("Case %d: -1\n\n", ++Case);
}
int main() {
int T;
scanf("%d", &T);
while (T--) {
tot = 0;
memset(head, 0, sizeof(head));
scanf("%d%d%d%d", &n, &m, &s, &e);
start = 0;
for (int i = 1; i <= m; i++) {
int x;
scanf("%d", &x);
start |= (1 << x);
}
for (int i = 1; i <= n - 1; i++) {
int x, y;
scanf("%d%d", &x, &y);
add(x, y); add(y, x);
}
bfs();
}
return 0;
}