如下面第一个图的九宫格中,放着 1 到 8 的数字卡片,还有一个格子空着。与空格子相邻的格子中的卡片可以移动到空格中。经过若干次移动,可以形成第二个图所示的局面。
我们把第一个图的局面记为:12345678.
把第二个图的局面记为:123.46758
显然是按从上到下,从左到右的顺序记录数字,空格记为句点。
本题目的任务是已知九宫的初态和终态,求最少经过多少步的移动可以到达。如果无论多少步都无法到达,则输出 −1。
Input
输入第一行包含九宫的初态,第二行包含九宫的终态。
Output
输出最少的步数,如果不存在方案,则输出 −1。
input
12345678.
123.46758
output
3
思路:
1、找最少步数,最佳方案,最短路,显然是用广搜更合适。
2、此题的关键之处就在于如何剪枝。走过的状态需要标记,不然重复去走已经走过的路就会超内存。每一个状态都可以用唯一的一个九位数字来表示,“.”用数字9来表示,把走过的状态存入一个set。每次走到一个位置都判断一下,set中是否已经存在此位置。
3、直接用string来存储比用二维邻接矩阵要简单得多,注意在判断下一步是否可走时,还是需要二维数组来判断,这时需要字符串与二维数组的转换,通过找规律进行正确且简洁的转换。
详情见ac代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<string>
#include<cmath>
#include<cstring>
#include<queue>
#include<set>
#define inf 0x3f3f3f3f
using namespace std;
int nextx[4]={-1,0,1,0};
int nexty[4]={0,1,0,-1};
struct node
{
int x,cnt;
string s;
};
long long f(string s)
{
int i;
long long num=0,base=1;
for(i=0;i<=8;i++)
{
if(s[i]=='.')
num+=9*base;
else
num+=(s[i]-'0')*base;
base*=10;
}
return num;
}
int main()
{
set<long long> a;
queue<node> q;
node n,m;
int i,mi,mj,nx,ny,ans=-1;
string s1,s2;
cin>>s1>>s2;
for(i=0;i<=8;i++)
if(s1[i]=='.')
mi=i;
n.x=mi,n.cnt=0,n.s=s1;
q.push(n);
while(!q.empty())
{
n=q.front();
q.pop();
if(n.s==s2)
{
ans=n.cnt;
break;
}
a.insert(f(n.s));
mi=n.x/3,mj=n.x%3;
for(i=0;i<4;i++)
{
nx=mi+nextx[i];
ny=mj+nexty[i];
if(nx>=0&&nx<=2&&ny>=0&&ny<=2)
{
m.x=nx*3+ny,m.cnt=n.cnt+1,m.s=n.s;
swap(m.s[n.x],m.s[m.x]);
if(a.count(f(m.s))==0)
q.push(m);
}
}
}
cout<<ans<<endl;
return 0;
}