我有话说:
这是一道bfs。因为他要移动每一个石头或者机器人。换成dfs的话,一个是不知道目标状态(最小步数),二是容易爆栈。既然是bfs,那么要考虑一下如何判重,想法是转换成二进制,对于编号上的格子是否有石头或者机器人采用1或0表示。但是,数组开太小会RE太大会TLE,后来看了一个大神的题解,选择了一个恰好的maxstate。
#include <iostream>
#include <cstdio>
#include <vector>
#include <queue>
#include <algorithm>
#include <cstring>
using namespace std;
struct State{
int robot,tree,d;
int x,y;
};
const int maxstate=(1<<15)*15+10;
int T,n,m,s,t,kase=1,init_tree,vis[1<<15][15];
vector<int>G[20];
State st[maxstate];
int fa[maxstate];
void Init()
{
scanf("%d%d%d%d",&n,&m,&s,&t);
memset(vis,0,sizeof(vis));
memset(fa,0,sizeof(fa));
for(int i=0;i<20;i++)G[i].clear();
init_tree=0;//清空变量
s--;t--;
for(int i=0;i<m;i++)
{
int stone;
scanf("%d",&stone);
init_tree|=(1<<(stone-1));//节省空间,全部-1
}
init_tree|=(1<<s);
int a,b;
for(int i=0;i<n-1;i++)
{
scanf("%d%d",&a,&b);
G[a-1].push_back(b-1);
G[b-1].push_back(a-1);
}
}
void print(int ans){
if(fa[ans])print(fa[ans]);
printf("%d %d\n",st[ans].x+1,st[ans].y+1);
}
int solve(){
int front=0,rear=1;
State& start=st[front];
start.d=0;
start.robot=s;
start.tree=init_tree;
start.x=start.y=0;
fa[front]=-1;
while(front<rear)
{
State& u=st[front];
if(u.robot==t){// 得解
printf("%d\n",u.d);
print(front);
return 1;
}
for(int i=0;i<n;i++)if(u.tree&(1<<i))//有机器人或石头
for(int j=0;j<G[i].size();j++){
if(u.tree&(1<<G[i][j]))continue;//有障碍
State& v=st[rear];
v.d=u.d+1;
v.robot=u.robot;
v.tree=u.tree-(1<<i)+(1<<G[i][j]);//移动
if(i==u.robot)v.robot=G[i][j];
if(vis[v.tree][v.robot])continue;
vis[v.tree][v.robot]=1;
fa[rear]=front;
v.x=i;
v.y=G[i][j];
rear++;
}
front++;
}
printf("-1\n");
return 0;
}
int main()
{
scanf("%d",&T);
while(T--)
{
Init();
printf("Case %d: ",kase++);
solve();
printf("\n");
}
return 0;
}