[数据结构]八数码(暴力,解答树,BFS+hash)

/*
Name:八数码(BFS+hash)

Actor:HT

Time:2015年6月22日

Error Reporte:

1.memcmp==0 代表匹配成功

2.memcpy(&+数组名,&+数组名,sizeof(数组名))

}
*/

#include"stdio.h"
#include"iostream"
#include"string.h"

using namespace std; 

int map[1000000][9];		//看做无限大队列,其中每个元素都具有9个点,也就是说每个元素都是一张图
int goal[9];
int ans[1000000];		//答案,移动的步数,也就是深度,要对应每个元素


const int my[4] = { -1, 0, 1, 0 };
const int mx[4] = { 0, 1, 0, -1 };				//图上移动,这样很方便  分别为上右下左
const int mz[4] = { -3, 1, 3, -1 };				//串上移动

int hashhead[1000000] = { 0 };			//无数个空hash的表头,每个表头用于存储hash值一样的一类“map元素的序号”,下标是个hash值
int hashtable[1000000] = { 0 };			//无数个指向空的hash的指针,每个指针的下标和值都是“map元素的序号”;其实就是一个“序号”组成的链表

int fa[10000000] = { 0 };		//写着玩
void print(int m)				//写着玩
{
	int i;
	for (i = 0; i < 9; i++)
	{
		cout <<map[m][i]<< " ";
		if (i % 3 == 2) cout << endl;
	}
}


int ahash(int rear)
{
	int i,t=0;
	for (i = 0; i < 9; i++)				//hash数值设定,把所有的情况归结到几个hash值中
	{
		t *= 10;
		t += map[rear][i];
		t %= 1000000;
	}
	int rearlyhash = hashhead[t];		//找到这个hash数值应该对应的表的表头的真值(某个map元素的元素序号)
	while (rearlyhash)			//沿着这条链表开始搜索
	{
		if (memcmp(map[rearlyhash], map[rear], sizeof(map[rear])) == 0)	return 0;
		rearlyhash = hashtable[rearlyhash];
	}
	hashtable[rear] = hashhead[t];		//这个新来的序号(rear)的下一个指向表头
	hashhead[t] = rear;					//新来的序号成为了新的表头
	return 1;
}

int bfs()
{
	int zero,x,y;		//零点在串的位置,以及在图的坐标
	int i;
	int front = 1, rear = 2;
	ans[front] = 0;
	while (front < rear)
	{
		if (memcmp(map[front],goal,sizeof(goal)) == 0)  return front;
		for (i = 0; i < 9; i++)
		if (map[front][i] == 0)
		{
			zero = i;
			break;
		}											//先找到0点
		x = zero % 3;								//分别为0   1   2
		y = zero / 3;								//分别为0   1   2
		for (i = 0; i < 4; i++)
		{
			int newx = x + mx[i], newy = y + my[i], newz= zero + mz[i];
			if (newx > 2 || newx < 0 || newy > 2 || newy < 0)	continue;
			memcpy(&map[rear], &map[front], sizeof(map[front]));
			map[rear][zero] = map[front][newz];
			map[rear][newz] = map[front][zero];	//生成新的map,准备放入队列
			ans[rear] = ans[front] + 1;
			fa[rear] = front;					//写着玩,印图用
			if (ahash(rear)==1) rear++;
		}
		front++;
	}
}

int main()
{
	int i,sum;
	for (i = 0; i < 9; i++)
		cin >> map[1][i];
	for (i = 0; i < 9; i++)
		cin >> goal[i];
	sum = bfs();
	cout << ans[sum]<<endl;
	for (i = sum; fa[i] != 0; i = fa[i])		//写着玩
	{
		print(i);
		cout << "\n\n";
	}
	system("pause");
}


下面给出一个Java版本..


package acm;

import java.util.*;
import java.io.*;

public class Acm {

	static public String mapString; 

//	public int zeroPoint[];	// 0 and 1 is the location in map, well 3 is the location in string
	
	public Map<Integer, Set> hashtable;
	
	public Queue<EachString> bfstable;
	
	public class EachString {
		
		// the class for the string and his dfs times
		
		String theString;
		
		int theTimes;

		public EachString(char[] tmp) {
			theString = new String(tmp);
			theTimes = 0;
		}
		
		public EachString() {
			theTimes = 0;
		}
	};
	
	public static int[] direction = {-3, +3, -1, +1};
	
	public Acm() {
		hashtable = new HashMap<Integer, Set>();
		bfstable = new LinkedList<EachString>();
	}
	
	public int getZeroPoint(String mapNow) {
		int zeroPoint;		// the location in string
		for(int i = 0; i < mapNow.length(); i++) {
			if (mapNow.charAt(i) == '0' ) {
				zeroPoint = i;
				return zeroPoint;
			}
		}
		// false
		return zeroPoint = 0;
	}
	
	public boolean PutToHash(String theString){
		// check and push
//		System.out.println(theString);
		int nowHash = Integer.parseInt(theString) / 100000000;
		Set <String> thisSet = hashtable.get(nowHash);
		if (thisSet != null) {
			if (!thisSet.contains(theString)) {
				thisSet.add(theString);
				return true;
			}
		}
		else {
			thisSet = new TreeSet<String>();
			thisSet.add(theString);
			hashtable.put(nowHash, thisSet);
			return true;
		}
		return false;
	}
	
	public void BFS() {
		EachString theMapEachString = new EachString();
		theMapEachString.theString = mapString;
		bfstable.add(theMapEachString);
		while(!bfstable.isEmpty()) {
			EachString nowEachString = bfstable.poll();
//			System.out.print("nowString" + nowString);
			int nowZeroPoint = getZeroPoint(nowEachString.theString);
//			char[][] nowMapString = new char[3][3];
//			nowMapString = nowString.toCharArray();
			for (int i : direction) {
				int tmp = nowZeroPoint + i;
				if (tmp > 8 || tmp < 0) {
					continue;
				}
				if ((i == 1 || i == -1) && tmp / 3 != nowZeroPoint / 3) {
					continue;
				}
				
				if (nowEachString.theString.equals("123456780")) {
					System.out.println("Finishde!  " + nowEachString.theTimes);
					return;
				}

				char[] newChar = nowEachString.theString.toCharArray();
				char trans = newChar[tmp];
				newChar[tmp] = newChar[nowZeroPoint];
				newChar[nowZeroPoint] = trans;
				EachString theNewEachString = new EachString(newChar);
				if (PutToHash(theNewEachString.theString)) {
					theNewEachString.theTimes = nowEachString.theTimes + 1;
					bfstable.add(theNewEachString);
				}
			}
		}
	}
	
	public static void main(String[] args) {
		 Acm acm = new Acm();
		 Scanner scanf = new Scanner(System.in);
		 acm.mapString = scanf.nextLine();
		 acm.BFS();
	}
	
	// 1234567890  
	/*   0 1 2 3 x
	 * 0 1 2 3
	 * 1 4 5 6
	 * 2 7 8 0
	 * 3     
	 * y
	 * 
	 * 0 1 2 | 3 4 5 | 6 7 8
	 * 1 3 6   0 4 8   2 5 7
	 */

}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值