我们把第一个图的局面记为:12345678.
把第二个图的局面记为:123.46758
显然是按从上到下,从左到右的顺序记录数字,空格记为句点。
本题目的任务是已知九宫的初态和终态,求最少经过多少步的移动可以到达。如果无论多少步都无法到达,则输出-1。
123.46758
46758123.
经典把数码搜索的题目,值得好好研究一下。
1,以前学的一门科目上的例题,用来讲解深度搜索和广度搜索的。
2,acm中也有很多类似的题目,这题可以采用a*算法
3,大致的思路就是,结合优先队列,康拓排序判断重复,进行搜索
4,urld是一定的方向,可以输出自行模拟是否正确。
Java代码:
注意java优先队列的用法,
import java.util.Arrays;
import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.Scanner;
class MyComp implements Comparator<node> {
@Override
public int compare(node o1, node o2) {
return o1.f-o2.f;///小的优先
}
}
class node {
int a[][] = new int [3][3] ;
int x=0;
int y=0;
String states ;
int d;
int w;
int f;///估价函数f=d+w;
public node(){
for(int i=0;i<3;i++)Arrays.fill(a[i],0) ;
states = "" ;
x=0;
y=0;
}
};
public class Main {
static int temp[][] = new int[3][3];
static int MAXN=1000000;///最多是9!
static int fac[]={1,1,2,6,24,120,720,5040,40320,362880};///康拖展开判重0!1!2!3!4!5!6!7!8!9!
static boolean vis[] = new boolean [MAXN];///标记
static int addx[]={-1,1,0,0};
static int addy[]={0,0,-1,1};
static int e;///目标状态,cantor展开对应的值
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner in = new Scanner(System.in) ;
int arry [] = new int[9] ;
String cc ;
cc = in.next() ;
for(int i=0;i<9;i++){
if(cc.charAt(i)=='.')arry[i]=9;
else arry[i]=cc.charAt(i)-'0';
}
int k=0;
node h = new node() ;
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
h.a[i][j]=arry[k++];
if(h.a[i][j]==9){
h.x=i;
h.y=j;
}
}
}
cc = in.next() ;
int it=0;
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
if(cc.charAt(it)=='.')temp[i][j]=9;
else temp[i][j]=cc.charAt(it)-'0';
it++;
}
}
///判断是否可解
int check [] = new int [9];
int c=0;
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
if(h.a[i][j]==9)check[c++]=0;
else check[c++]=h.a[i][j];
}
}
int sum1=0;
for(int i=0;i<9;i++){
if(check[i]==0)continue;
for(int j=0;j<i;j++){
if(check[j]>check[i]){
sum1++;
}
}
}
c=0;
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
if(temp[i][j]==9)check[c++]=0;
else check[c++]=temp[i][j];
}
}
int sum2=0;
for(int i=0;i<9;i++){
if(check[i]==0)continue;
for(int j=0;j<i;j++){
if(check[j]>check[i]){
sum2++;
}
}
}
if(sum1%2!=sum2%2){//开始状态的逆序数和目标状态的逆序数奇偶性不同,无解!
System.out.println("-1");
return;
}
///无解判断结束
e = cantor(temp);
Arrays.fill(vis, false);
vis[cantor(h.a)]=true;
PriorityQueue<node> qq = new PriorityQueue<node>(new MyComp()) ;
qq.clear();
qq.offer(h) ;
while(!qq.isEmpty()){
node top=qq.poll();
if(cantor(top.a)==e){
System.out.println(top.states.length());
return ;
}
int ch[][] = new int [3][3];
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
ch[i][j]=top.a[i][j];
}
}
for(int i=0;i<4;i++){
int newx=top.x+addx[i];
int newy=top.y+addy[i];
if(newx>=0&&newx<3&&newy>=0&&newy<3){
int tt = ch[newx][newy] ;
ch[newx][newy] = ch[top.x][top.y] ;
ch[top.x][top.y] = tt;
if(!vis[cantor(ch)]){
node pp = new node();
for(int kk=0;kk<3;kk++){
for(int kkk=0;kkk<3;kkk++){
pp.a[kk][kkk] = ch[kk][kkk];
}
}
//memcpy(pp.states,top.states,sizeof(top.states));
pp.states = top.states ;
pp.x=newx;
pp.y=newy;
pp.d=top.d+1;
pp.w=get(ch);
pp.f=pp.d+pp.w;
if(i==0)pp.states+="u";
if(i==1)pp.states+="d";
if(i==2)pp.states+="l";
if(i==3)pp.states+="r";
if(pp.f<=100){
qq.offer(pp);
vis[cantor(pp.a)]=true;}
}
//swap(ch[newx][newy],ch[top.x][top.y]);
tt = ch[newx][newy] ;
ch[newx][newy] = ch[top.x][top.y] ;
ch[top.x][top.y] = tt;
}
}
}
}
static int cantor(int m[][])///康拖展开求该序列的hash值
{
int s[] = new int [9];
int k=0;
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
s[k++]=m[i][j];
}
}
int sum=0;
for(int i=0;i<9;i++)
{
int num=0;
for(int j=i+1;j<9;j++)
if(s[j]<s[i])num++;
sum+=(num*fac[9-i-1]);
}
return sum+1;
}
static int get(int m[][]){///获得开始状态和目标状态,“错位个数”
int ret=0;
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
if(temp[i][j]!=m[i][j]){
ret++;
}
}
}
return ret;
}
}