历届试题 九宫重排 广度优先搜索+康拓排序

 历届试题 九宫重排   时间限制: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;
	}

}

    原文作者:九宫格问题
    原文地址: https://blog.csdn.net/fans_ac/article/details/60479048
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞