CDOJ 414 Eight Puzzle 八数码

貌似当时都是双向BFS写的,现在自己写,就想先写单向的,然后就先是MLE,然后发现标记数组太大,于是学了一发康托展开,然后就是TLE,然后就发现需要记录状态,怎么记录呢,改了改发现就改成DFS的记忆化搜索了,然后又去学姿势,发现是从终点开始往回BFS,就能把所有情况都找到,并且BFS的过程中就可以记录下来,然后就AC了。

在这过程中也发现了一篇好文章,八数码八境界

广搜+哈希+打表 代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
using namespace std;
#define maxs 362880
#define maxn 363000
const int aim = 123456780;
char str[30];
int mark[maxn];
int fact[10];
int powint(int x, int a)
{
	int ans = 1;
	for (int i = 0; i < a; ++i)
		ans *= x;
	return ans;
}
int cantor(int now)
{
	int ans = 0;
	int num[9];
	for (int i = 0; i < 9; ++i)
	{
		num[i] = now % 10;
		now /= 10;
	}
	for (int i = 0; i < 9; ++i)
	{
		int tmp = 0;
		for (int j = 0; j < i; ++j)
		{
			if (num[i] > num[j])
				++tmp;
		}
		ans += tmp*fact[i];
	}
	return ans;
}
int read()
{
	int re = 0;
	int n = strlen(str);
	for (int i = 0; i < n; ++i)
	{
		if (str[i] == 'x')
			re *= 10;
		if (str[i] >= '1'&&str[i] <= '9')
			re = re * 10 + str[i] - '0';
	}
	return re;
}
int pos_0(int now)
{
	int pos = -1;
	for (int i = 0; i < 9; ++i)
	{
		int tmp = now % 10;
		if (tmp == 0)
		{
			pos = i;
			break;
		}
		now /= 10;
	}
	return pos;
}
int down(int now)
{
	int re = now, pos = pos_0(now);
	if (pos >= 3)
	{
		int pos2 = pos - 3;
		int x1 = re / powint(10, pos) % 10;
		int x2 = re / powint(10, pos2) % 10;
		re += (x2 - x1)*powint(10, pos);
		re += (x1 - x2)*powint(10, pos2);
		return re;
	}
	else
		return -1;
}
int up(int now)
{
	int re = now, pos = pos_0(now);
	if (pos < 6)
	{
		int pos2 = pos + 3;
		int x1 = re / powint(10, pos) % 10;
		int x2 = re / powint(10, pos2) % 10;
		re += (x2 - x1)*powint(10, pos);
		re += (x1 - x2)*powint(10, pos2);
		return re;
	}
	else
		return -1;
}
int right(int now)
{
	int re = now, pos = pos_0(now);
	if (pos % 3 != 0)
	{
		int pos2 = pos - 1;
		int x1 = re / powint(10, pos) % 10;
		int x2 = re / powint(10, pos2) % 10;
		re += (x2 - x1)*powint(10, pos);
		re += (x1 - x2)*powint(10, pos2);
		return re;
	}
	else
		return -1;
}
int left(int now)
{
	int re = now, pos = pos_0(now);
	if ((pos + 1) % 3 != 0)
	{
		int pos2 = pos + 1;
		int x1 = re / powint(10, pos) % 10;
		int x2 = re / powint(10, pos2) % 10;
		re += (x2 - x1)*powint(10, pos);
		re += (x1 - x2)*powint(10, pos2);
		return re;
	}
	else
		return -1;
}
void BFS_init()
{
	memset(mark, -1, sizeof(int)*maxn);
	queue<int> que;
	mark[cantor(aim)] = 0;
	que.push(aim);
	while (!que.empty())
	{
		int now = que.front();
		int cnt = mark[cantor(now)];
		que.pop();
		int u, d, l, r;
		u = up(now), d = down(now), l = left(now), r = right(now);
		if (u != -1)
		{
			int cu = cantor(u);
			if (mark[cu] == -1)
			{
				que.push(u);
				mark[cu] = cnt + 1;
			}
		}
		if (d != -1)
		{
			int cd = cantor(d);
			if (mark[cd] == -1)
			{
				que.push(d);
				mark[cd] = cnt + 1;
			}
		}
		if (l != -1)
		{
			int cl = cantor(l);
			if (mark[cl] == -1)
			{
				que.push(l);
				mark[cl] = cnt + 1;
			}
		}
		if (r != -1)
		{
			int cr = cantor(r);
			if (mark[cr] == -1)
			{
				que.push(r);
				mark[cr] = cnt + 1;
			}
		}
	}
}
int main()
{
	//freopen("input.txt", "r", stdin);
	//康托展开+BFS+从目标往回搜索记录所有状态 or 双向BFS or A*搜索
	fact[0] = 1;
	for (int i = 1; i < 10; ++i)
		fact[i] = i*fact[i - 1];
	BFS_init();
	while (gets(str))
	{
		int now = read();
		int ans = mark[cantor(now)];
		if (ans >= 0)
			printf("%d\n", ans);
		else
			printf("unsolvable\n");
		memset(str, 0, sizeof(str));
	}
	//system("pause");
	//while (1);
	return 0;
}

你可能感兴趣的:(CDOJ 414 Eight Puzzle 八数码)