https://blog.csdn.net/wcr1996/article/details/43631771
感谢这位博主,学了很多,代码相当优秀
很有难度的一道题
思路的确不难,就是bfs搜索,但是具体实现起来还是很花时间的,数据结构还是比较好表示的,但是直接用结构体来表示石头和机器人位置会会超时,所以需要用到状态压缩
代码在原来的基础上加了部分注释,方便回顾时理解
#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iomanip>
#include<assert.h>
#include<vector>
#include<list>
#include<map>
#include<set>
#include<sstream>
#include<stack>
#include<queue>
#include<string>
#include<bitset>
#include<algorithm>
#pragma warning(disable:4996)
#define me(s) memset(s,0,sizeof(s))
#define _for(i,a,b) for(int i=(a);i<(b);++i)
#define _rep(i,a,b) for(int i=(a);i<=(b);++i)
#define Max(a,b) (a)>(b)?(a):(b);
#define Min(a,b) (a)<(b)?(a):(b);
using namespace std;
typedef pair <int, int> pii;
typedef long long ll;
typedef unsigned long long llu;
const int INT_INF = 0x3f3f3f3f;
const int INT_M_INF = 0x7f7f7f7f;
const ll LL_INF = 0x3f3f3f3f3f3f3f3f;
const ll LL_M_INF = 0x7f7f7f7f7f7f7f7f;
const int dr[] = { 0, -1, 0, 1, -1, -1, 1, 1 };
const int dc[] = { -1, 0, 1, 0, -1, 1, -1, 1 };
const int MOD = 1e9 + 7;
const double pi = acos(-1.0);
const double eps = 1e-15;
const int maxn = 15;
const int maxstate = (1 << maxn)*maxn + 10; //机器人和石头的位置状态总数是1<<maxn,注意这个是不区分机器人和石头的,所以还要考虑机器人位置
int n, m, s, t;
int g[maxn][maxn];
int fa[maxstate], dist[maxstate];
bool vis[maxstate][maxn];
typedef int state[2];
typedef int go[2];
state st[maxstate];
state k[maxstate];
void read()
{
me(g); me(fa); me(dist); me(vis); me(st); me(k);
scanf("%d%d%d%d", &n, &m, &s, &t);
st[1][1] = s - 1; st[1][0] = 1 << (s - 1); //st[1][1]存储了机器人的位置,也就是st[1][0]对应得二进制位
_for(i, 0, m) {
int k; scanf("%d", &k);
st[1][0] |= 1 << (k - 1); //存储石头位置
}
_for(i, 0, n - 1) {
int u, v; scanf("%d%d", &u, &v);
g[u - 1][v - 1] = g[v - 1][u - 1] = 1;//树转化为图
}
}
int bfs()
{
int front = 1, rear = 2;
while (front < rear) {
state &s = st[front]; //提取队首节点
if (s[1] == t - 1) return front; //判断是否达到目标状态
_for(i, 0, n) {
if (!(s[0] & (1 << i))) continue; //找到石头或者机器人
_for(j, 0, n) {
if ((s[0] & (1 << j)) || !g[i][j]) continue; //找到一个可以石头和机器人可以转移的空位
state &e = st[rear]; //扩展状态
memcpy(e, s, sizeof(s));
if (i == s[1]) e[1] = j; //更新机器人位置
e[0] ^= 1 << i | 1 << j; //交换位置
k[rear][0] = i + 1; k[rear][1] = j + 1; //记录操作
dist[rear] = dist[front] + 1; fa[rear] = front; //更新步数,记录前驱方便打印
if (!vis[e[0]][e[1]]) { rear++; vis[e[0]][e[1]] = true; } //判重
}
}
++front;
}
//全部搜索完依旧没有达到目标,说明无解
return 0;
}
void print(int a) //递归打印
{
if (!fa[a]) return;
print(fa[a]);
printf("%d %d\n", k[a][0], k[a][1]);
return;
}
int main()
{
int T, kcase = 0;
scanf("%d", &T);
while (T--) {
read();
int ans = bfs();
printf("Case %d: %d\n", ++kcase, ans ? dist[ans] : -1);
print(ans);
printf("\n");
}
}