1. 程式人生 > >歷屆試題 九宮重排 廣度優先搜尋+康拓排序

歷屆試題 九宮重排 廣度優先搜尋+康拓排序

 歷屆試題 九宮重排   時間限制:1.0s   記憶體限制:256.0MB 問題描述   如下面第一個圖的九宮格中,放著 1~8 的數字卡片,還有一個格子空著。與空格子相鄰的格子中的卡片可以移動到空格中。經過若干次移動,可以形成第二個圖所示的局面。

  我們把第一個圖的局面記為:12345678.
  把第二個圖的局面記為:123.46758
  顯然是按從上到下,從左到右的順序記錄數字,空格記為句點。
  本題目的任務是已知九宮的初態和終態,求最少經過多少步的移動可以到達。如果無論多少步都無法到達,則輸出-1。 輸入格式   輸入第一行包含九宮的初態,第二行包含九宮的終態。 輸出格式   輸出最少的步數,如果不存在方案,則輸出-1。 樣例輸入 12345678.
123.46758 樣例輸出 3 樣例輸入 13524678.
46758123. 樣例輸出 22

經典把數碼搜尋的題目,值得好好研究一下。

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;
	}

}