HDU 1010 Temper of the Bone

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_22812319/article/details/79198827

一、题目描述

      帮助doggie走出迷宫。迷宫由‘S’(起点)、‘X’(墙,不可通过)、‘D’(终点)、和‘.’(可走格子)组成。给定时间T,doggie每秒走一格,要求不可重复走,且刚好在T秒内走到终点D。如果有这样的路径,输出“YES”,否则“NO”。

二、样例

输入:

 
  
4 4 5 S.X. ..X. ..XD .... 3 4 5 S.X. ..X. ...D 0 0 0
输出:

NO
YES

三、分析

     深搜DFS问题。从起点开始,doggie每秒有4种走法,即上、下、左、右,下一秒又在上一次的基础上有4种选择。我们要做的就是对这所有的情况剪枝。

1、边界。遇到迷宫的边缘,或者代表无法通过的X,不再继续搜索;

2、重复。已经走过的区域不再重复搜索;

3、奇偶剪枝。这个不太容易想到。可以这样考虑:先计算起点到终点的最短距离d,由于有墙的存在,给的时间走过的步数T减去最短距离d,也就是需要绕路走的步数 t = T - d。这个绕路步数必须是偶数,否则无法到达终点。

4、时间。如果给的时间超过可走的步数+1,则一定无法到达。具体可以看这个样例:

   2 4 7
   S..D
   ....

    可走块数sum为6,时间T为7,刚好走完所有块到达终点。若sum < T - 1,一定无法到达。   

    另外要注意的就是递归,要小心跳出条件和恢复上一层。

四、代码

   
/**********************************************
*时间:2018-01-29
*内容:深搜+剪枝
*技巧:搜索的时候剪枝一定要考虑完全,能剪的都
       剪掉,否则容易超时;递归思路要清晰
***********************************************/
#include<iostream>
#include<cstring>
#include<cmath>
#include <stdlib.h>
using namespace std;

int dx[4]={1,0,-1,0},dy[4]={0,-1,0,1};
int n,m,t,sum;   //记录迷宫大小和时间,可走的块数
int sx,sy,ex,ey; //记录起点和终点坐标
char maze[7][7];
bool record[7][7];//记录迷宫是否被走过
bool flag = false;

void dfsMaze(int nx,int ny,int layer)
{
    if(layer == t ){ //跳出条件
        if(maze[nx][ny] == 'D' ) flag = true;
        return;
    }
    for(int i = 0; i < 4; ++ i){
        //排除边界情况
        if(nx + dx[i] < 0 || nx + dx[i] == n || ny + dy[i] < 0 || ny + dy[i] == m) continue;
        //对墙 和 已经走过的部分 剪枝
        if(maze[nx + dx[i]][ny + dy[i]] == 'X' || !record[nx + dx[i]][ny + dy[i]]) continue;
        //如果在时间到之前就走到D,也无法走出迷宫。剪枝
       if(layer < t - 1 && maze[nx + dx[i]][ny + dy[i]] == 'D') continue;
        record[nx+dx[i]][ny+dy[i]] = false; //记录该块已经走过
        nx = nx + dx[i];
        ny = ny + dy[i];

        //进入下一层搜索
        dfsMaze(nx,ny,++ layer);
        //恢复
        if(flag) return; //只要找到一条路线,就不再寻找
        record[nx][ny] = true;
        layer --;
        nx = nx - dx[i];
        ny = ny - dy[i];

    }
}
int main()
{
    while(true){//读入数据
        cin>>n>>m>>t;
        if(n==0) break;
        memset(record,true,sizeof(record));
        flag = false;
        sum = 0;
        for(int i = 0;i < n; ++ i){
            for(int j = 0;j < m; ++ j){
                cin >> maze[i][j];
                if(maze[i][j] == '.') sum++;
                //记录终点和起点位置
                if(maze[i][j] == 'D'){ex = i;ey = j;}
                if(maze[i][j] == 'S'){sx = i;sy = j;record[i][j] = false;}
            }
        }
        //如果可走的步数小于时间-1,或者需要绕弯走的步数是奇数,不可到达
        if(sum < t - 1 || (t - (abs(sx - ex) + abs(sy - ey))) % 2)cout<< "NO" <<endl;
        else{
            dfsMaze(sx,sy,0);
            if(flag) cout << "YES" << endl;
            else cout << "NO" << endl;
        }
    }
}




猜你喜欢

转载自blog.csdn.net/qq_22812319/article/details/79198827