(A星,优先队列,Hash函数,路径记录)POJ 1007 Eight

题目链接:http://poj.org/problem?id=1077

题目大意:经典八数码问题, 给出初始状态, 求到终止状态的路径.

分析:A星,优先队列,Hash函数,路径记录.

/*A星,优先队列,Hash函数,路径*/

#include<iostream>
#include<map>
#include<string>
#include<queue>
#include<cstdio>
#include<cstring>
#include<cstdlib>
using namespace std;
#define maxn 362886
#define PRIME 362885
#define whatever 10
int tmp[10];
char goal[10] = { "123456780" };
//int rule[10][4] = { { 0, 0, 0, 0 }, { 1, 1, 0, 0 }, { 2, 2, 2, 0 }, { 0, 3, 3, 0 }, { 4, 4, 0, 4 }, { 5, 5, 5, 5 }, { 0, 6, 6, 6 }, { 7, 0, 0, 7 }, { 8, 0, 8, 8 }, { 0, 0, 9, 9 } };
int dx[4] = { 0, -1, 0, 1 }, dy[4] = { -1, 0, 1, 0 };
struct NODE
{
	int map[3][3];
	int x0, y0;
	int sta;
	int hash;
	int f, g, h;
	bool operator < (const NODE &a)	const
	{
		if (a.f != f)
			return a.f < f;
		else
			return a.g < g;
	}
}t, u;
int mark[maxn];
struct
{
	int num; 
	int dir;
}PRE[maxn];
int flag;
int PreJudge(int a[])
{
	int sum = 0;
	for (int i = 0; i < 8; i++)
	for (int j = i + 1; j < 9; j++)
	if (a[j] && a[i] && a[i] > a[j])
		sum++;
	return sum % 2 == 0 ? true : false;
}
int map_to_int()
{
	int res = 0;
	for (int i = 0; i < 3; i++)
	for (int j = 0; j < 3; j++)
		res = res * 10 + t.map[i][j];
	return res;
}
int HASH(int sta)
{
	int p = sta%PRIME;
	while (mark[p] != 0 && mark[p] != sta)
		p = (p + 1) % PRIME;
	return p;
}
int get_h()
{
	char s[35];
	sprintf(s, "%d", t.sta);
	int cnt = 0;
	for (int i = 0; i < 9; i++)
	if (s[i] != '0'&&s[i] != goal[i])
		cnt++;
	return cnt;
}

void A_star()
{
	priority_queue<struct NODE> Q;
	t.sta = map_to_int();	t.hash = HASH(t.sta);	t.g = 0; t.h = get_h();	t.f = t.g + t.h;	
	PRE[t.hash].num = -1;	PRE[t.hash].dir = -1;
	Q.push(t);
	if (t.sta == 123456780)
	{
		flag = 1;
		return;
	}
	mark[t.hash] = t.sta;

	while (!Q.empty())
	{
		u = Q.top();	Q.pop();
		for (int dir = 0; dir < 4; dir++)
		{

			memcpy(t.map, u.map, sizeof(u.map));		
			//t = u;
			int x = u.x0 + dx[dir], y = u.y0 + dy[dir];
			if (0 <= x&&x < 3 && 0 <= y&&y < 3)
			{
				t.map[u.x0][u.y0] = u.map[x][y];	t.map[x][y] = 0;

				t.sta = map_to_int(); t.hash = HASH(t.sta);	
				if (mark[t.hash] == 0)
				{
					t.g = u.g + 1; t.h = get_h();	t.f = t.g + t.h;	t.x0 = x;	t.y0 = y;
					PRE[t.hash].num = u.hash;
					PRE[t.hash].dir = dir;

					Q.push(t);
					if (t.sta == 123456780)
					{
						flag = 1;
						return;
					}
					mark[t.hash] = t.sta;
				}
			}
		}
	}
}
int main()
{
	freopen("f:\\input.txt", "r", stdin);
	int i, j, k;
	char str[30];
	gets(str);
	int len = strlen(str);
	int top = 0;
	j = k = 0;
	for (i = 0; i < len; i++)
	{
		if (k == 3)
		{
			j++;
			k = 0;
		}
		if ('1' <= str[i] && str[i] <= '8')
			t.map[j][k++] = tmp[top++] = str[i] - '0';
		else if (str[i] == 'x')
		{
			t.x0 = j;
			t.y0 = k;
			t.map[j][k++] = tmp[top++] = 0;
		}

	}
	if (PreJudge(tmp) == false)
		printf("unsolvable\n");
	else
	{
		flag = 0;
		memset(mark, 0, sizeof(mark));
		A_star();

		if (flag)
		{
			int ans[1000];
			int top1 = 0;
			int p = t.hash;
			while (PRE[p].dir != -1)
			{
				ans[top1++] = PRE[p].dir;
				p = PRE[p].num;
			}
			char str[5] = { "lurd" };
			for (top1--; top1 >= 0; top1--)
				printf("%c", str[ans[top1]]);
			printf("\n");
		}
		else
			printf("unsolvable\n");
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值