杭电1010——Tempter of the Bone(DFS、剪枝)

来源:互联网 发布:梦想小镇辅助mac 编辑:程序博客网 时间:2024/05/22 14:22

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

题目大意:

小狗从起点出发,能否在第t秒到达终点。

算法:

DFS一般用来判断是否能到达终点(只需找到一条可以到达终点的路径即可),但是此题的要求是在t秒到达终点。所以,用DFS遍历所有可以到达终点的路径,看是否有一条路径的到达时间正好是t秒。用DFS遍历其中一条路径时,将该路径上已经访问过的点标志成’X’,代表在这次的路径遍历中不能再访问改点。若此条路径不是所求路径(在t秒到达终点的路径)。则沿原路返回,换个方向继续搜索,将之前标志过的‘X’还原成‘.’,以便下条路径还可以经过该节点。该题相当于用DFS穷举出所有路径,直到找到一条在t秒到达终点的路径为止。可是有些情况不需要进行搜索就可以判断不存在符合要求的路径,此时需要“剪枝”。

剪枝策略

(1)奇偶剪枝
这里写图片描述
如上图所示,我们将迷宫的每个格子用0或1表示。可以很清晰的看出来,每个格子的上下左右相邻的格子的值均和该格子自身值不同。也就是说,如果只走一步的话,只能走到和其值不相同的格子里去。所以,如果要走到跟其值相同的格子中的话,只能走偶数步。走到跟其值不同的格子中的话只能走奇数步。也就是说:
0->0 或者 1->1 走偶数步
0->1 或者 1->0 走奇数步
因此,如果起点和终点的值相同,时间却是奇数,则肯定不行。如果起点和终点的值不同,时间却是偶数,也不行。
代码中奇偶剪枝的代码如下:

if((t+starti+startj+endi+endj)%2)//奇偶剪枝{    printf("NO\n");    continue;}

很容易证明t+starti+startj+endi+endj的值只能为偶数,简单说明一下:
如果起点和终点的值相同,则starti+startj+endi+endj为偶数,此时如果时间t为偶数的话,即t+starti+startj+endi+endj为偶数(偶数+偶数=偶数),则可能存在路径。
如果起点和终点的值不同,则starti+startj+endi+endj为奇数,此时如果时间t为奇数的话,即t+starti+startj+endi+endj为偶数(偶数+偶数=偶数),则可能存在路径。
反之,若t+starti+startj+endi+endj为奇数,则不可能存在符合要求的路径。

(2)剩余区域小于时间剪枝
如果迷宫中除去墙的所有的格子的数目小于时间t,则说明即使将所有可以走的格子走了一遍,时间也会小于t,则不会存在符合要求的路径。该部分代码为:

if(n*m-wall<t){    printf("NO\n");    continue;}

AC代码

# include<stdio.h># include<math.h>int n,m,t;char maze[10][10];int starti,startj,endi,endj,flag;int dx[4][2]={{-1,0},{1,0},{0,-1},{0,1}};void dfs(int px,int py,int time);int main(){    int i,j,wall;    while(scanf("%d%d%d",&n,&m,&t)==3)    {        wall=0;        flag=0;        if(n==0&&m==0&&t==0)            break;        for(i=0;i<n;i++)        {            for(j=0;j<m;j++)            {                scanf("%1s",&maze[i][j]);                if(maze[i][j]=='S')                {                    starti=i;                    startj=j;                }                else if(maze[i][j]=='D')                {                    endi=i;                    endj=j;                }                else if(maze[i][j]=='X')                {                    wall++;                }            }        }        if(n*m-wall<t)//剩余空间小于时间        {            printf("NO\n");            continue;        }        if((t+starti+startj+endi+endj)%2)//奇偶剪枝        {            printf("NO\n");            continue;        }        dfs(starti,startj,0);        if(flag==1)            printf("YES\n");        else            printf("NO\n");    }    return 0;}void dfs(int px,int py,int time){    if(px==endi&&py==endj&&time==t)    {        flag=1;        return ;    }    if(time>t)        return ;    if(px<0||px>=n||py<0||py>=m||maze[px][py]=='X')        return ;    int i;    for(i=0;i<4;i++)    {        maze[px][py]='X';        dfs(px+dx[i][0],py+dx[i][1],time+1);        maze[px][py]='.';//还原到原来的状态,以便下次搜索时可以访问该位置        if(flag==1)            return;    }}
0 0
原创粉丝点击