八数码——解题报告

题目描述

在3*3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给出一种初始布局和目标布局,为了使题目简单,设目标状态为:
123
804
765
找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变.


解题报告:

网上已有很多关于八数码的解法,大致有几种方法:深搜,广搜,双向广搜,A*,本解题报告实现了双广的代码,效率略低于A*。

大致思想如下,将起始状态和目的状态都表示成一个字符串,然后设置两个队列,两边分别想中间扩展,当找到相同的节点时,即为找到了一种方案,而广度搜索即找到的是最佳方案,即为题解。


import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Scanner;
import java.util.Set;


class Node {
	String nowStr;
	Node preNode;
	char howtom;
	int zero;
	
	Node(String nowStr,Node preNode,int zero,char howtom){
		this.nowStr = nowStr;
		this.preNode = preNode;
		this.zero = zero;
		this.howtom = howtom;
	}
}

public class N06EightShuMa {

	static String des = "123804765";
	static int[][] move = new int[][]{{-1,0},{0,1},{1,0},{0,-1}};
	static char[][] dch = new char[][]{{'u','d'},{'r','l'},{'d','u'},{'l','r'}};
	static int firstZero;
	static Set<String> firSet = new HashSet<String>();
	static Set<String> endSet = new HashSet<String>();
	static List<Set> list= new ArrayList<Set>(); 
	static List<Node> firList = new ArrayList<Node>();
	static List<Node> endList = new ArrayList<Node>();
	static Node stnode;
	static Node desnode;
	static int[] b = new int[2];
	static int[] c =new int[2];
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		String st = "";
		int[] a = new int[9];
		for(int i=0;i<9;i++){
			a[i] = sc.nextInt();
		}
		st=IntToStr(a);
		stnode = new Node(st,null,firstZero,' ');
		firList.add(stnode);
		desnode = new Node(des,null,4,' ');
		endList.add(desnode);
		firSet.add(st);
		list.add(firSet);
		endSet.add(des);		
		list.add(endSet);
		b[0]=b[1]=1;
		while(b[0]!=0&&b[1]!=0){
			if(b[0]<b[1]){
				if(expand(firList,0)){	//扩展起始队列
					return;
				}
				
			}else{
				if(expand(endList,1)){	//扩展目标队列	
					return;
				}
				
			}
		}
		while(b[0]!=0){
			if(expand(firList,0)){
				return;
			}
		}
		while(b[1]!=0){
			if(expand(endList,1)){
				return;
			}
		}
		System.out.println("不能到达!");
		return;
	}

	private static void prin(String str) {		//打印结果
		List<String> result = new ArrayList<String>();
		Node node =null;
		for(int i=0;i<firList.size();i++){
			node = firList.get(i);
			if(node.nowStr.endsWith(str)){
				break;
			}
		}
		while(node.preNode!=null){
			result.add(0,node.howtom+"");
			node = node.preNode;
		}
		for(int j=0;j<endList.size();j++){
			node = endList.get(j);
			if(node.nowStr.endsWith(str)){
				break;
			}
		}
		while(node.preNode!=null){
			result.add(node.howtom+"");
			node = node.preNode;
		}
		for(String s:result){
			System.out.print(s);
		}
		System.out.println();
		System.out.println(result.size());
	}


	@SuppressWarnings("unchecked")
	private static boolean expand(List<Node> que, int k) {		//扩展函数
		Node node = que.get(c[k]);
		int index = node.zero;
		b[k]--;
		for(int i=0;i<4;i++){
			int x = index/3+move[i][0];
			int y = index%3+move[i][1];
			if(x>=0&&x<=2&&y>=0&&y<=2){
				String str = swap(x*3+y,index,node.nowStr);
				Node temp  = new Node(str,node,x*3+y,dch[i][k]);
				if(list.get(1-k).contains(str)){
					que.add(temp);
					prin(str);
					return true;
				}
				if(!list.get(k).add(str)){
					continue;
				}				
				que.add(temp);
				b[k]++;
				
			}
		}
		c[k]++;
		return false;
	}


	private static String swap(int k, int index, String nowStr) {	//交换字符位置
		String te="";
		if(k<index){
			return te+nowStr.substring(0, k)+nowStr.charAt(index)+nowStr.substring(k+1,index)+nowStr.charAt(k)+nowStr.substring(index+1);
		}else{
			return te+nowStr.substring(0, index)+nowStr.charAt(k)+nowStr.substring(index+1,k)+nowStr.charAt(index)+nowStr.substring(k+1);
		}
		
	}


	private static String IntToStr(int[] a) {	//将int数组转换为字符串
		String te = "";
		for(int i=0;i<9;i++){
			te+=a[i];
			if(a[i]==0){
				firstZero = i;
			}
		}
		return te;
	}

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值