Tempter of the Bone--dfs加剪枝优化

来源:互联网 发布:chip数据 编辑:程序博客网 时间:2024/06/03 08:42
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 5S.X...X...XD....3 4 5S.X...X....D0 0 0
 

Sample Output
NO

YES

分析:这道题一开始我是直接用深搜求出最短路然后和时间比较,如果小于时间即成功,样例过了,但是提交超时,我以为是深搜的问题,于是我又用广搜做了一遍结果还是超时,后来我意识到是我的程序有问题,于是接触到了剪枝优化这个思想。

剪枝优化简单来说就是对于搜索所形成的树进行剪去不必要的路径,就是那些一定不可能达到结果的的路径就不必再进行搜索了,从而达到优化程序时间达到目的,这里先不做详述,因为接下里我会再写其他文章进行详述。

题目大意:给定起点和终点,问刚好在t步时能否到达终点。

解题思路

4个剪枝。

1.如果当前时间即步数(step) >= T 而且还没有找到D点,则剪掉。

2.设当前位置(x, y)到D点(dx, dy)的最短距离为s,到达当前位置(x, y)已经花费时间(步数)step,那么,如果题目要求的时间T - step < s,则剪掉。

3. 对于当前位置(x, y),如果,(T-step-s)是奇数,则剪掉(奇偶剪枝)。

4.如果地图中,可走的点的数目(xnum) < 要求的时间T,则剪掉(路径剪枝)。

根据:奇数+偶数=奇数; 偶数+偶数=偶数;所以为了保持相同的奇偶性必须加一个偶数的步数

奇偶剪枝的原理:abs(x-ex)+abs(y-ey)为奇,则说明到达终点肯定还要走奇数步,反之偶数步。于是得和abs(dep-t)即还需走的步数奇偶性协调。

好了,上代码:

import java.util.*;public class Main {    static Scanner in = new Scanner(System.in);    static int m,n,t,s1,e1,s2,e2;    static char[][] ma = new char[8][8];    static boolean[][] vis = new boolean[8][8];    static int[][] dir = { {0,1},{1,0},{0,-1},{-1,0}};     static boolean escape;    static void dfs(int x,int y,int de) {        int i,temp;          if (x==s2 && y==e2 && de==t){              escape=true; //时间正好的时候才能逃生              return;          }        //计算当前到终点的最短路与还需要的时间差,若小于0则路径剪枝          temp=Math.abs(t-de)-(Math.abs(s2-x)+Math.abs(e2-y));        if (temp<0 || ((temp&1)==1)) //temp如果是奇数的话也要剪枝              return;    int tx=0,ty=0;    for ( i = 0; i < 4; i++) {    tx=x+dir[i][0];    ty=y+dir[i][1];    if(tx<0||ty<0||tx>=n||ty>=m)    continue;if(!vis[tx][ty]&&ma[tx][ty]!='X') {  vis[tx][ty]=true;       dfs(tx,ty,de+1);      vis[tx][ty]=false;}}    } public static void main(String[] args) {while(in.hasNext()) {int cnt=0;n = in.nextInt();m = in.nextInt();t = in.nextInt();if(m==0&&n==0&&t==0)break;String s;for (int i = 0; i < n; i++) {s=in.next();for (int j = 0; j < s.length(); j++) {ma[i][j]=s.charAt(j);vis[i][j]=false;if(ma[i][j]=='S'){    s1=i;e1=j;  }if(ma[i][j]=='D'){  s2=i;e2=j;}if(ma[i][j]=='X'){ cnt++;}}}if(n*m-cnt<=t)   System.out.println("NO");else{      escape=false; vis[s1][e1]=true; dfs(s1,e1,0);   if(escape)   System.out.println("YES"); else   System.out.println("NO");}}}} 



其实上面用到的方法就是利用了奇偶剪枝,这里我贴上奇偶剪枝的介绍链接:https://baike.baidu.com/item/%E5%A5%87%E5%81%B6%E5%89%AA%E6%9E%9D/10385689?fr=aladdin

原创粉丝点击