题意:有一颗n (4≤n≤15) 个结点的树,其中一个结点有一个机器人,还有一些结点有石头。每步可以把一个机器人或者石头移到一个相邻结点。任何情况下一个结点里不能有两个东西(石头或者机器人)。输入每个石头的位置和机器人的起点和终点,求最小步数的方案。如果有多解,可以输出任意解。如图所示,s=1,t=5时,最少需要16步:机器人1-6,石头2-1-7,机器人6-1-2-8,石头3-2-1-6,石头4-3-2-1,最后机器人8-2-3-4-5。(本段摘自《算法竞赛入门经典(第2版)》)
分析:
直接使用BFS搜索即可,用cantor展开来标记状态。
代码:
#include <iostream>
#include <algorithm>
#include <fstream>
#include <string>
#include <cstring>
#include <vector>
#include <queue>
#include <cmath>
#include <cctype>
#include <stack>
#include <set>
using namespace std;
const int maxn = 15 + 5, INF = 10;
struct Node
{
int x, cantor, f, deep;
int path[2];
int a[maxn];
};
int T, x, y, n, m, s, t, ans, head, tail;
int a[maxn], tmp[maxn], v[600005];
vector< int > vec[maxn];
Node q[600005];
int Cantor(const int a[])
{
int pos = -1, res = 0, fac = 1;
for (int i = 1; i <= n; ++i)
{
if (a[i] == 1)
res += fac;
else if (a[i] == 2)
pos = i;
fac <<= 1;
}
res += ((1 << 15) * pos);
return res;
}
void print(int head)
{
if (q[head].f == -1)
return;
print(q[head].f);
printf("%d %d\n", q[head].path[0], q[head].path[1]);
}
int BFS()
{
memset(v, 0, sizeof(v));
head = 0;
tail = 0;
q[tail].x = s;
memcpy(q[tail].a, a, sizeof(a));
q[tail].cantor = Cantor(q[tail].a);
v[q[tail].cantor] = 1;
q[tail].f = -1;
q[tail++].deep = 0;
while (head != tail)
{
if (q[head].x == t)
return q[head].deep;
for (int i = 1; i <= n; ++i)
if (q[head].a[i])
{
for (int j = 0; j < vec[i].size(); ++j)
{
int u = vec[i][j];
if (!q[head].a[u])
{
memcpy(tmp, q[head].a, sizeof(q[head].a));
swap(tmp[i], tmp[u]);
int c = Cantor(tmp);
if (!v[c])
{
int pos = (q[head].x == i) ? u : q[head].x;
q[tail].x = pos;
memcpy(q[tail].a, tmp, sizeof(tmp));
q[tail].cantor = c;
q[tail].f = head;
q[tail].path[0] = i;
q[tail].path[1] = u;
q[tail++].deep = q[head].deep + 1;
v[c] = 1;
}
}
}
}
++head;
}
return -1;
}
int main()
{
scanf("%d", &T);
for (int C = 0; C < T; ++C)
{
memset(a, 0, sizeof(a));
scanf("%d%d%d%d", &n, &m, &s, &t);
for (int i = 1; i <= n; ++i)
vec[i].clear();
a[s] = 2;
for (int i = 0; i < m; ++i)
{
scanf("%d", &x);
a[x] = 1;
}
for (int i = 0; i < n - 1; ++i)
{
scanf("%d%d", &x, &y);
vec[x].push_back(y);
vec[y].push_back(x);
}
ans = BFS();
printf("Case %d: %d\n", C + 1, ans);
if (ans != -1)
print(head);
printf("\n");
}
return 0;
}