ZOJ-1217

27 篇文章 0 订阅

经典八码难题,又搞了我一晚上,所幸最后AC了,不过试着在POJ提交了下,TLE了。。HDU上也可以过,不知为毛。这题我最开始天真地直接单向BFS裸搜了,毫无疑问TLE,网上搜了搜,发现大牛竟然用A*做的。。完全不懂,还有一种是双向BFS,我改了下还是TLE,可能算法不对。最后经过长期思考,直接把12345678x这种最终状态反向BFS出所有有解的状态,即预处理了,存到map里面,加上状态的父节点和路径,这样的话根据输入可直接判出是否有解,然后打印路径,可能可以优化的地方是状态可以用hash表存,不知道时间上有没有提升,先不管了。。晚上搞的够恶心了

#include<cstdio>
#include<deque>
#include<map>

using namespace std;

namespace
{
	int c[3][3];
	int dir[4][2] = { { 0, 1 }, { 0, -1 }, { -1, 0 }, { 1, 0 } };
	char ch[4] = { 'l', 'r', 'd', 'u' };
	map<int, pair<int, char> > P;

	pair<int, int> fill(int num)
	{
		pair<int, int> res;
		for (int i = 2; i >= 0; i--)
			for (int j = 2; j >= 0; j--)
			{
				c[i][j] = num % 10;
				num /= 10;
				if (c[i][j] == 9)
				{
					res.first = i;
					res.second = j;
				}
			}
		return res;
	}

	int number()
	{
		int res = 0;
		for (int i = 0; i < 3; i++)
			for (int j = 0; j < 3; j++)
				res = res * 10 + c[i][j];
		return res;
	}

	void swap(int i1, int j1, int i2, int j2)
	{
		int temp = c[i1][j1];
		c[i1][j1] = c[i2][j2];
		c[i2][j2] = temp;
	}

	void print_path(int res)
	{
		while (res != 123456789)
		{
			putchar(P[res].second);
			res = P[res].first;
		}
		putchar('\n');
	}

	void bfs()
	{
		deque<int> Q;
		Q.push_back(123456789);
		P.clear();
		P[123456789] = make_pair(0, 0);
		while (!Q.empty())
		{
			int now = Q.front();
			Q.pop_front();
			pair<int, int> p = fill(now);
			for (int k = 0; k < 4; k++)
			{
				int i = p.first + dir[k][0];
				int j = p.second + dir[k][1];
				if (i >= 0 && i < 3 && j >= 0 && j < 3)
				{
					swap(p.first, p.second, i, j);
					int n = number();
					if (P.find(n) == P.end())
					{
						P[n] = make_pair(now, ch[k]);
						Q.push_back(n);
					}
					swap(p.first, p.second, i, j);
				}
			}
		}
	}
}

int main()
{
	char s[30];
	bfs();
	while (gets(s) != NULL)
	{
		int res = 0;
		for (int i = 0; s[i] != '\0'; i++)
			if (s[i] != ' ')
				res = res * 10 + (s[i] == 'x' ? 9 : (s[i] - '0'));
		if (P.find(res) != P.end())
			print_path(res);
		else
			puts("unsolvable");
	}
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值