8数码问题 A*搜索

这段时间看A*,然后就把经典问题八数码做了一遍。以前听朋友说过,自己实现的时候还是学到了不少东西。

 

八数码问题主要思想:

1.将3×3的table用一维字符串表示

2.一维字符串是共有9!个,因此用hash来散列

3.把问题转换为寻路问题,起点是初始状态,终点是目标状态,每移一下,相当于走了一步

 

我觉得八数码问题当中的估计函数(启发函数)是一个亮点:我自己想到的是用当前的字符串与 目标字符串比较,h=不在位的数。这个启发函数虽然不是很好,但是还是能做出来的。

 

同样,八数码解的判定也是个亮点:逆序数。转成一维以后,计算出不包含0的逆序数,然后奇偶性判断。这个是网上找到的方法,觉得非常牛,赞一下。

 

这些是自己的心得。附上代码:

 

import java.util.Date;

public class Mainx {

	public static void main(String[] argvv){
		DigitTable table = new DigitTable("578064321","123456780");
		Date dd = new Date();
		boolean res =table.run();
		if(!res){
			System.out.println("无解");
			return;
		}
		Long t = (new Date()).getTime()- dd.getTime();
		table.printStep();
		System.out.println("运行时间"+t+"毫秒");
	}
}
 
import java.util.Comparator;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.PriorityQueue;
import java.util.Set;

/**
 * @author coolgo
 */
public class DigitTable {

	private int stepx[] = { 0, 1, 0, -1 };// 上下左右交换
	private int stepy[] = { 1, 0, -1, 0 };// 上下左右交换
	private String startState;
	private String endState;
	private Hashtable<String, Node> tb = new Hashtable<String, Node>();
	public DigitTable(String start, String end) {
		startState = start;
		endState = end;
	}

	public boolean run() {
		if(!hasSolution()) return false;
		NodeComparator cmp = new NodeComparator();
		PriorityQueue<Node> open = new PriorityQueue<Node> (1000000,cmp);
		Set<String> close = new HashSet<String>();

		Node tmp = new Node(startState, endState, 0);
		tmp.f = tmp.g + tmp.h;
		open.add(tmp);
		tb.put(tmp.state, tmp);
		int t, zero;
		int x, y, nxtx, nxty;
		String cur, nxtStr;
		Node top, nxt;
		while (!open.isEmpty()) {
			top = open.poll();
			cur = top.state;
			close.add(cur);
			if (close.contains(endState))
				break;

			zero = cur.indexOf("0");
			x = zero / 3;
			y = zero % 3;
			for (int i = 0; i < 4; i++) {
				nxtx = x + stepx[i];
				nxty = y + stepy[i];
				if (nxtx >= 3 || nxtx < 0 || nxty < 0 || nxty >= 3)
					continue;
				t = nxtx * 3 + nxty;

				nxtStr = getNxtStr(cur, t, zero);
				if (tb.containsKey(nxtStr)) {
					if (close.contains(nxtStr))
						continue;
					nxt = tb.get(nxtStr);
					if (nxt.g > top.g + 1) {
						nxt.g = top.g + 1;
						nxt.f = nxt.g + nxt.h;
						nxt.parent = top;
					}
				} else {
					nxt = new Node(nxtStr, endState, top.g + 1);
					nxt.parent = top;
					tb.put(nxtStr, nxt);
					open.add(nxt);
				}
			}
		}
		return true;
	}

	/**
	 * 通过逆序数判断,是否有解
	 * 两个互相可达的状态对应序列逆序数的奇偶性应该相同 
	 * 1 2 3 4 5 6 8 7奇偶性为1
	 * 1 2 3 4 5 6 7 8奇偶性为0 
	 * 所以两状态相互不可达
	 * @return
	 */
	private boolean hasSolution() {
		return getReverseNum(startState)%2==getReverseNum(endState)%2;
	}
	
	private int getReverseNum(String str){
		int rs=0;
		char[] cs = str.toCharArray();
		for(int i =0; i< 9; i++){
			for(int j = 0; j <i; j++){
				if((cs[j]<cs[i])&&(cs[i]!='0'&&cs[j]!='0'))rs++;
			}
		}
		return rs;
	}

	public void printStep(){
		System.out.println("状态数"+tb.size());
		System.out.println("步骤数"+tb.get(endState).f);
		Node cur = tb.get(endState);
		while(!cur.parent.equals(cur)){
			printMap(cur.state);
			System.out.println("====");
			cur = cur.parent;
		}
		
	}
	private void printMap(String nxtStr) {
		
		for (int i = 0; i < 9; i += 3)
			System.out.println(nxtStr.substring(i, i + 3));

	}

	private String getNxtStr(String cur, int t, int zero) {
		char[] cs = cur.toCharArray();
		cs[zero] = cs[t];
		cs[t] = '0';
		return String.valueOf(cs);
	}

	/**
	 * 比较器
	 * @author coolgo
	 */
	public class NodeComparator implements Comparator<Node> {
		@Override
		public int compare(Node x, Node y) {
			return x.f - y.f;
		}
	}
}
 
/**
 * 每次变化后的状态
 * @author coolgo
 */
public class Node {

	/**
	 * f = g + h; h为估价函数
	 */
	public int f = 1 << 30;
	public int g = 1 << 30;
	public int h = 1 << 30;
	public String state = "";
	public Node parent = this;

	public Node(String str, String endState, int i) {
		state = str;
		h= getH(state, endState);
		g = i;
		f = g+h;
	}
	/**
	 * 估计函数:不在本位的数
	 * @param cur
	 * @param endState
	 * @return
	 */
	private int getH(String cur, String endState) {
		int x = 0;
		for (int i = 0; i < 9; i++) {
			x += (cur.charAt(i) == endState.charAt(i) ? 0 : 1);
		}
		return x;
	}
}
 

你可能感兴趣的:(F#,J#)