Tempter of the Bone

 

 

 本题要求在指定时间点到达目的地, 一开始用的广搜, 但是搜出的是最短路径, 理解错题意了... 使用深搜, 只要搜索到一个能在指定时间点到达目的地的路径就返回(由于深搜可能会爆栈, 所以要用到奇偶剪枝)

奇偶剪枝结论:若 t-[abs(ex-sx)+abs(ey-sy)] 结果为非偶数(奇数),则无法在t步恰好到达(奇偶剪枝详细说明请参考百度百科)

 

 

 

#include <iostream>
#include <cstring>
#include <cmath>
using namespace std;

int n, m, t, sx, sy, ex, ey, flag;
char map[10][10];
int vis[10][10];
int dir[4][2] = {{1,0},{0,1},{-1,0},{0,-1}};

void dfs(int x, int y, int ti)
{
	int dx, dy;
	if(flag == 1 || ti > t)	return ; 
	// 在规定时间内正好到达终点
	if(map[x][y] == 'D' && ti == t)
	{
		flag = 1;	// 找到了这么一条路 
		return ;	// 返回 
	}
	
	int tem = t - ti - abs(ex-x) - abs(ey-y);//剪枝的核心代码
	if(tem < 0 || tem & 1)//剪枝:如果剩余的步数已经不足以走到出口,且必须是偶数,偶数-偶数=偶数,奇数-奇数=偶数,
        return;
	// 四个方向遍历 
	for(int i = 0; i < 4; ++ i)
	{
		dx = x + dir[i][0];
		dy = y + dir[i][1];
		
		// 如果 越界 或 走到墙X 或 已访问过 
		if(dx < 0 || dx >= n || dy < 0 || dy >= m || map[dx][dy] == 'X' || vis[dx][dy])
			continue;
			
		// 新扩展的点标记走过, 对该点进行DFS 
		vis[dx][dy] = 1;
		dfs(dx, dy, ti + 1);
		// 回溯后将标记撤回 
		vis[dx][dy] = 0;
	}
	return ;
}

int main()
{
	while(cin >> n >> m >> t)
	{
		if(n == 0 && m == 0 && t == 0)	break;
		memset(vis, 0, sizeof(vis));
		
		for(int i = 0; i < n; ++ i)
		{
			cin >> map[i];
		}
		
		int wall = 0;
		flag = 0;
		for(int i = 0; i < n; i ++)
        {
            for(int j = 0; j < m; j ++)
            {
                if(map[i][j] == 'S')
                {
                    sx = i;
					sy = j;
                }
                if(map[i][j]=='D')
                {
                    ex = i;
					ey = j;
                }
                if(map[i][j]=='X')	wall ++;
            }
        }

		if(t > n * m - wall - 1)
		{
			cout << "NO" << endl;
			continue;
		}
		
		vis[sx][sy] = 1;
		dfs(sx, sy, 0);
	
		if(flag)	cout << "YES" << endl;
		else	cout << "NO" << endl;
	}
	
	return 0;
}

/*
4 4 5
S.X.
..X.
..XD
....
3 4 5
S.X.
..X.
...D
0 0 0
*/

  

posted @ 2019-09-23 16:40  青衫客36  阅读(261)  评论(0编辑  收藏  举报