杭电1010_Tempter of the Bone——java

Problem Description
The doggie found a bone in an ancient maze, which fascinated him a lot. However, when he picked it up, the maze began to shake, and the doggie could feel the ground sinking. He realized that the bone was a trap, and he tried desperately to get out of this maze.

The maze was a rectangle with sizes N by M. There was a door in the maze. At the beginning, the door was closed and it would open at the T-th second for a short period of time (less than 1 second). Therefore the doggie had to arrive at the door on exactly the T-th second. In every second, he could move one block to one of the upper, lower, left and right neighboring blocks. Once he entered a block, the ground of this block would start to sink and disappear in the next second. He could not stay at one block for more than one second, nor could he move into a visited block. Can the poor doggie survive? Please help him.
 

Input
The input consists of multiple test cases. The first line of each test case contains three integers N, M, and T (1 < N, M < 7; 0 < T < 50), which denote the sizes of the maze and the time at which the door will open, respectively. The next N lines give the maze layout, with each line containing M characters. A character is one of the following:

'X': a block of wall, which the doggie cannot enter; 
'S': the start point of the doggie; 
'D': the Door; or
'.': an empty block.

The input is terminated with three 0's. This test case is not to be processed.
 

Output
For each test case, print in one line "YES" if the doggie can survive, or "NO" otherwise.
 

Sample Input
 
 
4 4 5
S.X.
..X.
..XD
....
3 4 5
S.X.
..X.
...D
0 0 0
 

Sample Output
 
 
NO
YES

 题意:‘S’字符为入口,‘.’代表可以行走的路径,但是每个路径只可踩一次,‘X’为墙不可行走,‘D’为门,即为出口。输入为3个参数,第一个参数和第二个参数是这个迷宫的大小规模,最后一个参数T代表要在规定的步数走到门口。意思是在‘S’时,步数为0,刚好第T步走到‘D’则输出YES,否则输出NO。

 由于这道题要刚好在规定的步数踏出门口,则需要深搜DFS来搜索一条符合条件的路径。如果直接深搜,会TLE,需要剪枝。在这里需要奇偶剪枝,意思如下:


例如一个01矩阵:

0 1 0 1 0 1

1 0 1 0 1 0

0 1 0 1 0 1

1 0 1 0 1 0

0 1 0 1 0 1

由于只能横向和竖向走,则0到1(1到0)必然是奇数的步数,1到1(0到0)必然是偶数的步数。所以在这里,0到1(1到0)如果剩余的步数是偶数,又或者1到1(0到0)时剩余的步数是奇数,都可以直接剪枝。

比较有一张地图

S . . .
. . . .
. . . .
. . . .
. . . D
S的坐标为X1,Y1,D坐标为X2,Y2
要求从S到D,此时,S到D的最短距离S’ = | X1 - X2| + |Y1 - Y2|

如果地图中有障碍物

S . . X
X X . X
. . . X
. X X X
. . . D

此时的最短距离S = S’ + 4,为了绕开障碍,不管偏移几个点,偏移的距离都是最短的距离加上一个 偶数的距离。

这里有几个点可以直接剪枝:

1、如果当前的步数 大于或者等于 所要求的的步数没到门,直接剪。

2、当前位置到D点的最短距离S,到当前位置已经花费的步数Step,如果 要求的步数T - Step < S(说明即使走最短的路都无法在规定的步数内到达),剪。

3、如果T - Step - 最短距离S 是奇数,剪。

4、如果地图中,可以走的数目(即‘.’的数量)比要求的步数(T)还少,直接输出NO。

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Main {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        List<String> list = new ArrayList<String>();
        while(sc.hasNextInt()){
            int row = sc.nextInt();
            int column = sc.nextInt();
            int second = sc.nextInt();
            //读取换行符
            String s = sc.nextLine();
            if(row == 0 && column == 0 && second == 0)
                break;
            //迷宫
            char[][] c = new char[row][column];
            int[][] flag = new int[row][column];
            int x = 0,y = 0;
            int dx = 0,dy = 0;
            int count = 0;//记录可以走的点树数
            for(int i = 0;i < row;i++){
                String data = sc.nextLine();
                for(int j = 0;j < column;j++){
                    c[i][j] = data.charAt(j);
                    if(c[i][j] == 'S'){
                        x = i;
                        y = j;
                    }
                    else if(c[i][j] == '.')
                        count++;
                    else if(c[i][j] == 'D'){
                        count++;
                        dx = i;
                        dy = j;
                    }
                }
            }
            //最小步数
            int minStep = Math.abs(dy - y) + Math.abs(dx-x);
            //如果可以走的点数少于second(门开的时间),不可达,或者最小步数都大于时间,也不可达
            if(count < second || minStep > second){
                list.add("NO");
            }
            else{
                String result;
                if(dfs(row,column,second,x,y,0,c,flag,dx,dy))
                    result = "YES";
                else
                    result = "NO";
                list.add(result);
            }

        }
        for(String s : list){
            System.out.println(s);
        }
    }

    public static boolean dfs(int row,int column,int second,int x,int y,int current,char[][] c,int[][] flag,int dx,int dy){
        if(x>=0&&x<row&&y>=0&&y<column&&c[x][y] == 'D' && second == current)
            return true;
        if(x>=0&&x<row&&y>=0&&y<column&&c[x][y]!='X'&&flag[x][y]==0){
            //如果当前到达的点离终点的最短距离大于剩余的秒数,剪枝
            int minStep = Math.abs(dy-y) + Math.abs(dx-x);
            if(minStep > second - current)
                return false;
            //目的地的步数一定等于两点之间的最短距离加上一个偶数
            //如果当前点到目的地的最短距离 + 剩余的步数等于偶数,剪枝
            else if((second - current - minStep) % 2 != 0)
                return false;
            flag[x][y] = 1;
            //上搜索
            boolean b1 = dfs( row, column, second, x-1, y, current+1, c, flag,dx,dy);
            if(b1)  return b1;

            //左搜索
            boolean b2 = dfs( row, column, second, x, y-1, current+1, c, flag,dx,dy);
            if(b2) return b2;

            //下搜索
            boolean b3 = dfs( row, column, second, x+1, y, current+1, c, flag,dx,dy);
            if(b3) return b3;

            //右搜索
            boolean b4 = dfs( row, column, second, x, y+1, current+1, c, flag,dx,dy);
            if(b4) return b4;

            flag[x][y] = 0;
            return false;
        }
        else{
            return false;
        }
    }
}


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值