AgPro

导航

A*算法解八数码(九宫格)问题

//POJ-1077
#include <iostream>
#include <algorithm>
using namespace std;

const int M = 362880;
struct node
{
	int state;//当前点表示方式
	char action;//到达当前点的动作
	int table;//0表示未访问,1表示在open表,2表示在close表,用于hash判重
	int h;//h表示当前点到目标点的估计代价
	int g;//g()表示原点到当前点的代价
	int f;//f() = g() + h()
}hash[M];
int rnums[10], total;
int nums[10];
int fac[10] = {0, 1, 1, 2, 6, 24, 120, 720, 5040, 40320};
char actions[10][6] = //每个位置对应的后续状态为有限个
{
	{' '},
	{'r', 'd'},
	{'l', 'r', 'd'},
	{'l', 'd'},
	{'u', 'r', 'd'},
	{'u', 'l', 'r', 'd'},
	{'u', 'l', 'd'},
	{'u', 'r'},
	{'u', 'l', 'r'},
	{'u', 'l'}
};
int manhattan[10][10] = //第i个数及其所处不同位置的Manhattan路径长度 
{
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
	{-1, 0, 1, 2, 1, 2, 3, 2, 3, 4},
	{-1, 1, 0, 1, 2, 1, 2, 3, 2, 3},
	{-1, 2, 1, 0, 3, 2, 1, 4, 3, 2},
	{-1, 1, 2, 3, 0, 1, 2, 1, 2, 3},
	{-1, 2, 1, 2, 1, 0, 1, 2, 1, 2},
	{-1, 3, 2, 1, 2, 1, 0, 3, 2, 1},
	{-1, 2, 3, 4, 1, 2, 3, 0, 1, 2},
	{-1, 3, 2, 3, 2, 1, 2, 1, 0, 1},
	{-1, 4, 3, 2, 3, 2, 1, 2, 1, 0}

};
int init_state = 0, end_state = 123456789;
int heap[M], top = 0;//保存的值为hash的key值,key值是由state的 reverseNum * fac 计算的
void BUheapify(int k)
{
	while(k > 1 && hash[heap[k/2]].f > hash[heap[k]].f)
	{
		swap(heap[k],heap[k/2]);
		k /= 2;
	}
}
void TDheapify(int k, int N)
{
	int i;
	while(2 * k < N)
	{
		i = 2 * k;
		if(hash[heap[i]].f > hash[heap[i+1]].f) 
			i++;
		if(!(hash[heap[k]].f > hash[heap[i]].f)) 
			break;
		swap(heap[k],heap[i]);
		k = i;
	}
}
void PQinit() {top = 0;}
int PQempty() {return top == 0;}
void PQinsert(int key) 
{
	heap[++top] = key; 
	BUheapify(top);
}
int PQdelmin()
{
	swap(heap[1],heap[top]);
	TDheapify(1, top-1); 
	return heap[top--];
}
int exp(int k)
{
	int res = 1;
	while(k--) res *= 10;
	return res;
}
int moveR(int state) {	return state + 1;}
int moveL(int state) {	return state - 1;}
int moveU(int state)
{
	int n, x, y;
	n = 9 - state % 10 + 1;
	x = state % exp(n); 
	y = state / exp(n);
	y = y/1000*1000 + y%1000/100 + y%1000%100*10;
	return x - 3 + y*exp(n);
}
int moveD(int state)
{
	int n, x, y;
	n = 9 - state % 10 + 1;
	x = state % exp(n); 
	y = state / exp(n);
	x = x % exp(n-3) + (x / exp(n-3) % 10 *100 + x /exp(n-3) /10) * exp(n-3);
	return x + y*exp(n)+3;
}
int getNum(int state, int p) 
{
	return state/exp(9-p)%10;
}
int getRevNum(int state)
{
	int total = 0;
	for(int i = 1; i <= 8; ++i) 
		rnums[i] = 0;
	for(int i = 1; i <=8 ; ++i)
	{
		int num = getNum(state, i);
		nums[i] = num;
		for(int j = i-1; j >= 1; --j)
		{
			if(nums[j] > num)
			{
				++rnums[i]; 
				++total;
			}
		}
	}
	return total;
}
int getHashNum(int state)
{
	getRevNum(state);
	int key = 0;
	for(int i = 1; i <= 8; ++i) 
		key += rnums[i] * fac[i];
	key += (9 - getNum(state,9)) * fac[9];
	return key;
}
int getManhattan(int state)//用作估价函数的h值
{
	int total = 0,k;
	for(int i = 1; i <= 8; ++i)
	{
		k = getNum(state, i);
		total += manhattan[k][i];
	}
	return total;
}
void output(int state)
{
	int key = getHashNum(state);
	char action = hash[key].action;
	if(action != 's')
	{
		if(action == 'l') {output(moveR(state)); cout << "l";}
		if(action == 'r') {output(moveL(state)); cout << "r";}
		if(action == 'u') {output(moveD(state)); cout << "u";}
		if(action == 'd') {output(moveU(state)); cout << "d";}
	}
}
void Best_First_Search()
{
	int x, state1, key1, state2, key2;
	char action;
	key1 = getHashNum(init_state);
	hash[key1].state = init_state;
	hash[key1].action = 's';
	hash[key1].table = 1;
	hash[key1].g = 0;
	PQinit(); 
	PQinsert(key1);
	while(!PQempty())
	{
		key1 = PQdelmin();
		hash[key1].table = 2;
		if(hash[key1].state == end_state) 
		{
			output(hash[key1].state);
			break;
		}

		x = hash[key1].state % 10;
		state1 = hash[key1].state;
		for(int i = 0; i <= 4; ++i)
		{
			action = actions[x][i];
			if(action != 'l' && action != 'r' && action != 'u' &&action != 'd') 
				continue;
			if(action == 'l') {state2 = moveL(state1); key2 = getHashNum(state2);}
			if(action == 'r') {state2 = moveR(state1); key2 = getHashNum(state2);}
			if(action == 'u') {state2 = moveU(state1); key2 = getHashNum(state2);}
			if(action == 'd') {state2 = moveD(state1); key2 = getHashNum(state2);}

			if(hash[key2].table == 1)
			{
				if(hash[key1].g + 1 < hash[key2].g)
				{
					hash[key2].g = hash[key1].g + 1;
					hash[key2].f = hash[key2].g + hash[key2].h;
					for(int j = top; j >= 2 ; --j) 
						BUheapify(j);
				}
			}
			else if(hash[key2].table == 0) 
			{
				hash[key2].state = state2;
				hash[key2].action = action;
				hash[key2].table = 1;
				hash[key2].g = hash[key1].g + 1;
				hash[key2].h = getManhattan(state2)*9;
				hash[key2].f = hash[key2].g + hash[key2].h;
				PQinsert(key2);
			}
			else if(hash[key2].table == 2) 
				continue;

		}
	}
}
int main()
{
	char num, trash;
	int blank;
	for(int i = 1; i <= 9; ++i)
	{
		cin.get(num);
		cin.get(trash);
		if(num != 'x') 
			init_state = init_state * 10 + int(num - '0');
		else 
			blank = i;
	}
	//2 3 4 1 5 x 7 6 8
	init_state = init_state * 10 + blank;
	Best_First_Search();

	return 0;
}

posted on 2010-06-21 16:03  AgPro  阅读(1910)  评论(0编辑  收藏  举报