1. 程式人生 > >廣度優先搜尋——經典的8數碼問題

廣度優先搜尋——經典的8數碼問題

話不多說,直接貼程式碼吧~

//廣度搜索-8數碼問題 

#include <iostream>
#include <cstring>
using namespace std;

const int Max = 8;
const int All = 363000;	//總的個數有9!= 362880,故取363000
int Fac[Max] = {1};		//康託展開需要用到的工具 
char a[All][9];		
bool visit[All];
char goal[9];
int dis[All];
int dir[4][2]={{-1,0},{1,0},{0,1},{0,-1}};	//搜尋時用到的四個方向 

void Init();	//輸入,以及初始化Fac 
int getValue(char* s);		//康託展開來Hash化局面!!!
bool check(int head);	//check是否已經到達目的狀態 
int bfs();			//所有是搜尋過程! 

int main()
{
	Init();
	int ans = bfs();
	if(ans == -1) cout << "No answers!" << endl;
	else cout << ans << endl;
	return 0;	
}

void Init()
{
	for(int i=0; i<9; ++i)
		cin >> a[0][i];
	for(int i=0; i<9; ++i)
		cin >> goal[i];
	for(int i=1; i<Max; ++i)
		Fac[i] = Fac[i-1] * i;
}
int getValue(char* s)
{
	int sum = 0, cnt, key = 1;
	for(int i=0; i<9; ++i)
	{
		cnt = 0;
		for(int j=i+1; j<9; ++j)
			if(s[j] < s[i]) ++cnt;
		sum += cnt * Fac[Max-i];
	}
	return sum;
}
inline bool check(int head)
{
	for(int i=0; i<9; ++i){
		if(a[head][i] != goal[i])
			return false;
	}
	return true;
}
int bfs(){
	int head = 0, tail = 1;
	int x, y, z, nx, ny, nz;
	while(head < tail){
		if(check(head)) return dis[head];

		for(int i=0; i<9; ++i){
			if(a[head][i] == '0'){
				x = i / 3;
				y = i % 3;
				z = i;
				break;
			}
		}
		
		for(int i=0; i<4; ++i){
			nx = x + dir[i][0];
			ny = y + dir[i][1];
			nz = 3*nx + ny;

			if(nx<0 || ny<0 || nx>2 || ny>2)
				continue;

			for(int i=0; i<9; ++i)
				a[tail][i] = a[head][i];
			a[tail][z] = a[tail][nz];
			a[tail][nz] = '0';			

			int t = getValue(a[tail]);
			if(!visit[t]){
				visit[t] = true;
				dis[tail] = dis[head] + 1;
				++tail;
			}
		}
		++head;
	}	
}


今天剛學了“寬搜”,見識到了神奇的“康託展開”的hash化的方式,也懂得了“康託逆展開”的方法,明天我會把這兩個的程式碼也放上來!

寬搜的精髓,個人覺得在於兩個點——

1. 如何如何構造搜尋樹

2. 如何判斷局面重複

只要做好這兩個點,其他的,水到渠成!!!加油,明天繼續做多點“寬搜”題目,為了明天下午的ccf認證!!!