题意:
类似于八数码问题;这里要求给定初始状态经过最大步数转移的得到的末状态,然后输出初始状态到末状态的最短路径。
思路:
这里重要的是求出末状态,本来我是想用dfs求这个末状态的,但后面想了一下,bfs最后的状态其实就是我们要求的末状态,
所以直接bfs到最后(front==rear的时候),然后再输出状态和路径。
代码如下:
<span style="font-size:18px;">#include<iostream>
#include<cstring>
#include<cstdio>
#include<stack>
using namespace std;
#define maxn 500000
typedef int State[9];
char ch[]={'U','D','L','R'};
int dx[]={-1,1,0,0};
int dy[]={0,0,-1,1};
int vis[maxn],fact[10];
State st[maxn];
typedef struct
{
int fa;
int step;
}P;
P p[maxn];
//康托展开
int Insert(int s)
{
int code=0;
for(int i=0;i<9;i++)
{
int cnt=0;
for(int j=i+1;j<9;j++)
if(st[s][j]<st[s][i])
cnt++;
code+=fact[8-i]*cnt;
}
if(vis[code])
return 0;
vis[code]=1;
return 1;
}
int bfs()
{
int i,j;
memset(p,-1,sizeof(p));
memset(vis,0,sizeof(vis));
Insert(0);
int front=0,rear=1;
while(front<rear)
{
int z;
for(z=0;z<9;z++)
if(st[front][z]==0)
break;
int x=z/3;
int y=z%3;
for(i=0;i<4;i++)
{
int xx=x+dx[i];
int yy=y+dy[i];
int zz=xx*3+yy;
if(xx<0||xx>=3||yy<0||yy>=3)
continue;
memcpy(st[rear],st[front],sizeof(st[front]));
st[rear][z]=st[front][zz];
st[rear][zz]=st[front][z];
if(Insert(rear))
{
p[rear].fa=front;
p[rear].step=i;
rear++;
}
}
front++;
}
for(int i=0;i<9;i++)
{
if(i!=0&&i%3==0)
printf("\n");
printf("%d ",st[front-1][i]);
}
printf("\n");
stack<int>S;
int k=rear-1;
while(p[k].fa!=-1)
{
S.push(p[k].step);
k=p[k].fa;
}
while(!S.empty())
{
char c=ch[S.top()];
printf("%c",c);
S.pop();
}
printf("\n");
}
int main()
{
int i,j,k,Case=0,t;
fact[1]=1;
for(i=2;i<=9;i++)
fact[i]=i*fact[i-1];
scanf("%d",&t);
while(t--)
{
k=0;
for(i=0;i<3;i++)
for(j=0;j<3;j++)
scanf("%d",&st[0][k++]);
printf("Puzzle #%d\n",++Case);
memset(vis,0,sizeof(vis));
bfs();
printf("\n");
}
return 0;
}
</span>