首页 > 代码库 > HDU 1010 Tempter of the Bone heuristic 剪枝法

HDU 1010 Tempter of the Bone heuristic 剪枝法

本题就是考剪枝法了。

应该说是比较高级的应用了。因为要使用heuristic(经验)剪枝法。要总结出这个经验规律来,不容易。我说这是高级的应用也因为网上太多解题报告都没有分析好这题,给出的程序也很慢,仅仅能过掉,由此看来很多人没有做好这道题。


这里我需要更正一下网上流行的说法:奇偶剪枝法。

其实本题使用奇偶剪枝法并不能太大提高速度,只能说仅仅让使用奇偶剪枝过掉。所以网上说本题使用奇偶剪枝的,其实并不能提高速度。

原因:

奇偶剪枝只能剪枝一次,不能在递归的时候剪枝,因为只要初始化位置符合奇偶性,那么之后的任意方格都会符合奇偶性。

故此理论上也是不能提高速度的,当然本人也实验过多次,证实奇偶剪枝至少对本题来说用处不大。


本题的主要剪枝法应该是一条: 最大空格数和步数比较。就是说如果生下的空格数位grids,而需要走T步,grids < T的时候,就可以判定为NO了。

当然还有第二条剪枝:如果当前位置到目标位置最少需要steps步,而需要走T步,那么steps > T,就可以判定为NO了。

不过事实证明只需要使用第一个剪枝法就可以了。

第二条剪枝用处也不大,原因:递归的格子很少,计算距离差并不能提高多少速度。


如我下面递归循环中只使用一条主要剪枝就足够了,不超100ms。虽然没有做到0ms,不过速度已经是够快的了。

0ms估计需要进一步的剪枝,有大牛,请指教一下。有空要深入研究一下A*算法才行了。

int sr = 0, sc = 0, dr = 0, dc = 0, n, m, grids, Tsec;
vector<string> maze;

bool escapeMaze()
{
	if (sr == dr && sc == dc)
	{
		if (Tsec == 0) return true;
		return false;
	}
	if (grids < Tsec) return false;
	if (Tsec == 0) return false;

	maze[sr][sc] = '$';
	grids--; Tsec--;
	if (sr+1 <(int)maze.size() && maze[sr+1][sc] == '.')
	{
		sr++;
		if (escapeMaze()) return true;
		sr--;
	}
	if (sc+1 < (int)maze[0].size() && maze[sr][sc+1] == '.')
	{
		sc++;
		if (escapeMaze()) return true;
		sc--;
	}
	if (sc > 0 && maze[sr][sc-1] == '.')
	{
		sc--;
		if (escapeMaze()) return true;
		sc++;
	}
	if (sr > 0 && maze[sr-1][sc] == '.')
	{
		sr--;
		if (escapeMaze()) return true;
		sr++;
	}
	maze[sr][sc] = '.';
	grids++; Tsec++;
	return false;
}

int main()
{
	while (scanf("%d %d %d", &n, &m, &Tsec) && n)
	{
		grids = n * m - 1;
		maze.clear(); maze.resize(n);
		for (int i = 0; i < n; i++)
		{
			cin>>maze[i];
			for (int j = 0; j < m; j++)
			{
				if (maze[i][j] == 'S') sr = i, sc = j; //别忘记了这里是'S'
				else if (maze[i][j] == 'D') dr = i, dc = j, maze[i][j] = '.';
				else if (maze[i][j] == 'X') grids--;
			}
		}
		int t = Tsec - (abs(dr - sr) + abs(dc-sc));
		if (t < 0 || (t & 1) || grids < Tsec) puts("NO");
		else if (escapeMaze()) puts("YES");
		else puts("NO");
	}
	return 0;
}