我們把第一個圖的局面記爲: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;
}
}