HDOJ-1010基础的迷宫问题(DFS)

C语言 码拜 9年前 (2015-05-11) 1155次浏览 0个评论

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
题目大意:给出起始位置和终点位置,要求在指定的时间刚好到达终点时间,每移动一步一秒,并且不能返回。

问题一:我的代码不知道哪里出错了,自己举一些例子总是过不了,更不用说AC了,请教大神们看看哪里有问题。
问题二:小弟还是不太理解这题里面剪枝的具体作用,我的想法是:比如第R步距离终点是奇数步,且时间也剩下奇数,那么再无论向剩下的3个方向中的哪一个走一步,走了R+1步,距离终点自然变成了偶数步,且剩下的时间也是偶数的,那奇偶剪枝的意义不就没有了么?

#include <stdio.h>
#include <stdlib.h>
#define true 1
#define false 0
int flag;
int atx,aty,time,n,m;
//atx,aty记录终点坐标
char map[26][26];
void bfs(int x,int y,int step);
int main()
{
    int n,m,time,i,j;//n行m列
    int x,y;//起始地点
    while(scanf("%d%d%d",&n,&m,&time)!=EOF)
    {
        if(n==0&&m==0&&time==0)
            break;
            flag=false;
            //画出一个新的地图
        for(i=0;i<n;i++)
        {
            scanf("%s",map[i]);
            for(j=0;j<m;j++)
            {
                if(map[i][j]==""S"")
                {
                    x=i;
                    y=j;
                }
                if(map[i][j]==""D"")
                {
                    atx=i;
                    aty=j;
                }
            }
        }
        bfs(x,y,time);
        if(flag)
            printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}
void bfs(int x,int y,int step)
{//判断当前位置是否为终点;且时间刚好合适
    int temp;
    if(x<0||y<0||x>=n||y>=m)//>=因为x和y的值来源于数组序号,最大序号为n-1
        return;
    if(flag==true||x==atx&&y==aty&&step==0)
    {
        flag=true;
        return;
    }
    //奇偶剪枝
    temp=abs(x-atx)+abs(y-aty)+step;
    if(temp%2!=0)return;

    //核心环节:深度搜索
    map[x][y]=""X"";
    if(map[x+1][y]!=""X""){
        bfs(x+1,y,step-1);
        if(flag)return;
    }
    if(map[x-1][y]!=""X""){
        bfs(x-1,y,step-1);
        if(flag)return;
    }
    if(map[x][y+1]!=""X""){
        bfs(x,y+1,step-1);
        if(flag)return;
    }
    if(map[x][y-1]!=""X""){
        bfs(x,y-1,step-1);
        if(flag)return;
    }
    map[x][y]=""."";
}
50分
奇偶剪枝的作用,当门在T秒开时,假设T为奇数,abs(x-atx)+abs(y-aty)的值为偶数(或者是T为偶数,另一个结果为奇数)。此时无论怎么走都不可能走出去的(因为此时到门的时间一定是偶数,具体要什么数学证明我也搞不懂),不用再进行搜索,直接可以判断无法出去。速度不是很快吗?

引用 楼主 qq_23908539 的回复:

问题一:我的代码不知道哪里出错了,自己举一些例子总是过不了,更不用说AC了,请教大神们看看哪里有问题。

 if(map[x+1][y]!=””X””){
        bfs(x+1,y,step-1);
        if(flag)return;
    }
    if(map[x-1][y]!=””X””){
        bfs(x-1,y,step-1);
        if(flag)return;
    }
    if(map[x][y+1]!=””X””){
        bfs(x,y+1,step-1);
        if(flag)return;
    }
    if(map[x][y-1]!=””X””){
        bfs(x,y-1,step-1);
        if(flag)return;
    }
map[x+1] [y],map[x-1][y], map[x][y-1],map[x][y+1],这里面你没有对x+1,x-1,y-1,y+1其范围是否还在[0,N),[0,m)进行判断。这个有可能造成数组越界

引用 1 楼 mxway 的回复:

奇偶剪枝的作用,当门在T秒开时,假设T为奇数,abs(x-atx)+abs(y-aty)的值为偶数(或者是T为偶数,另一个结果为奇数)。此时无论怎么走都不可能走出去的(因为此时到门的时间一定是偶数,具体要什么数学证明我也搞不懂),不用再进行搜索,直接可以判断无法出去。速度不是很快吗?

也就是说奇偶剪枝的唯一作用就是在一开的时候判断下能否奇偶是否对等,而在后面的步骤中就没有用了?

引用 1 楼 mxway 的回复:

这里面你没有对x+1,x-1,y-1,y+1其范围是否还在[0,N),[0,m)进行判断。这个有可能造成数组越界

有判断啊,当刷新dfs参数的时候,也就是一进入dfs函数就会有个if语句来看他们是否出界。

引用 2 楼 qq_23908539 的回复:

也就是说奇偶剪枝的唯一作用就是在一开的时候判断下能否奇偶是否对等,而在后面的步骤中就没有用了?

可以这么说。

引用 3 楼 qq_23908539 的回复:

有判断啊,当刷新dfs参数的时候,也就是一进入dfs函数就会有个if语句来看他们是否出界。

如果当前x=0
if(map[x-1][y]!=””X””)
map[x-1][y]不就数组越界了吗?

引用 4 楼 mxway 的回复:

如果当前x=0
if(map[x-1][y]!=””X””)
map[x-1][y]不就数组越界了吗?

对啊,所以当把x-1也就是-1作为新的参数传进数组的时候会有直接因为通不过

 if(x<0||y<0||x>=n||y>=m)

语句而被
return了

引用 5 楼 qq_23908539 的回复:
Quote: 引用 4 楼 mxway 的回复:

如果当前x=0
if(map[x-1][y]!=””X””)
map[x-1][y]不就数组越界了吗?

对啊,所以当把x-1也就是-1作为新的参数传进数组的时候会有直接因为通不过

 if(x<0||y<0||x>=n||y>=m)

语句而被
return了

不仅是返回的问题
map[-1][y]这个会直接给你Runtime error的。

引用 6 楼 mxway 的回复:

不仅是返回的问题
map[-1][y]这个会直接给你Runtime error的。

的确是栈溢出了,可我看网上的那些AC了的答案都是这样写的。小弟刚想了很久也试了一下 还是不知道该怎么写,希望前辈提醒一下具体该怎么做。
还有我又想到一个问题,就是我的程序刚开始在while scanf 后面不用加个getchar()吃回车么?
小弟感激不尽!

int dir[4][2] = {{0,1},{0,-1},{1,0},{-1,0}};

int check(int x,int y)
{
	if(x>=0 && y>=0 && x<n && y<m)
		return 1;
	return 0;
}

void dfs(int x, int y, int step)
{
	int temp;
	int dx,dy;

	if(flag == true || x==atx && y==aty && step==0)
	{
		flag = true;
		return;
	}

	temp=abs(x-atx)+abs(y-aty)+step;

	if(temp%2!=0)return;
	map[x][y] = ""X"";
	for(int i=0; i<4; i++)
	{
		dx = x+dir[i][0];
		dy = y+dir[i][1];
		if(check(dx,dy) && map[dx][dy]!=""X"")
		{
			dfs(dx,dy,step-1);
		}
	}
	map[x][y] = ""."";
}

CodeBye 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明HDOJ-1010基础的迷宫问题(DFS)
喜欢 (0)
[1034331897@qq.com]
分享 (0)

文章评论已关闭!