HDU1010_一个很有意思的DFS

1.题目链接。题目的大意就是给定一个迷宫,判定是否可以在规定的时间内从起点走到终点。这和一般的DFS有着一定的区别,这里我们不需要最短路,只需要一条最合适的道路,因为这个门的打开是在规定时间打开的,去早了也不行,去晚了也不行,所以所以这里我们需要找到一条合适的路。这个体现程序中也就是我们在搜索的过程中需要加上判断的条件。

2.分析:其实这个问题不是很困难,搜索就是一种优雅的暴力嘛,我们只需要把每一条可行的路径的时间计算,然后判断是否可行即可。显然,这是需要减支的,否则就会T掉。关于这个题的减支,很多博客都提出了奇偶减支,但是很少有说明为什么的,这里我就来解释一下,当然大佬们不写并不是不会,只是觉得显然的事情,没有必要再浪费口舌。

3.减支:我觉得这个题的减支可以分为三个方面。

(1)普通的剪枝:这个很显然了,这个也就是dfs的出口,这个估计大家都会写。就是在搜索的过程中,首先应该判断坐标的合法性,当前已经走了多少步,是否还有时间等等一些细节的问题。局部的代码大概如下


    if(x<0||x>=n||y<0||y>=m)
        return;
    if(time>t||(time==t&&(ex!=x||ey!=y)))
    {
        flag=false;
        return ;
    }

    if(ex==x&&ey==y&&time==t)
    {
        flag=true;
        return ;
    }
    if(flag)
        return;

(2)全局的剪枝:这个应该叫做先决条件,或者可以开始搜索的必要条件。这个条件就是:m*n-wall<=t.其中m和n是这个图的大小,wall是这个图中X的数量,t是规定的时间。为什么会有这个条件,其实这个不等式就是在告诉我们这样的信息,你这个图剩下的可以行走的点要足够我t时间内走过的。什么意思,我想大家应该应该很明白了,就是说我有t秒的时间,那么我在这t秒的时间内一定是需要走过t个点的,你这个图给我留下的空间要足够,否则我t秒需要走t个点,但是你图中只有t-1点,这显然是不行的。然后就是相等的条件,为什不是小于而是小于等于?因为起点的原因。

(3)然后就是最重要的奇偶剪枝了,这个我们上边就说了,很多博客也提过了,但是很少有说明为什么的。我先给出结论:从起点到达终点的最短路径和从当前点到达目标点路径长度同奇偶(这里的长度我们定义为走过的格子的数量),其实这个就是哈密尔顿距离。为什么是这样的,我们首先来思考一个问题,最短路径,那就是直接不考虑障碍物的时候,起点到终点的的横纵坐标之差,假设我们在行走的过程总有障碍物,那么我们要绕开它,由于我们不能沿着对角线行进,那么我们只能避开这个障碍物,我们只能绕行,这个绕行就是一次两个格子,所以其实最短的路径和我们真实路径永远都是相差2k的,所以二者同奇偶。

知道了这些剪枝,下边的代码就很好写了。我始终坚信,程序是一个很确定的东西,不能有半点模糊。下面是代码:

#include<bits/stdc++.h>
using namespace std;
char a[10][10];
int n,m,t;
int sx,sy,ex,ey;
bool flag;
int dir[4][2]={1,0,0,1,0,-1,-1,0};
void DFS(int x,int y,int time)
{
    if(x<0||x>=n||y<0||y>=m)
        return;
    if(time>t||(time==t&&(ex!=x||ey!=y)))
    {
        flag=false;
        return ;
    }

    if(ex==x&&ey==y&&time==t)
    {
        flag=true;
        return ;
    }
    if(flag)
        return;
    int temp=(t-time)-(abs(x-ex)+abs(y-ey));
    if(temp<0||temp&1)
        return;
    for(int i=0;i<4;i++)
    {
        int xx=x+dir[i][0];
        int yy=y+dir[i][1];
        if(a[xx][yy]!='X')
        {
            a[xx][yy]='X';
            DFS(xx,yy,time+1);
            a[xx][yy]='.';
            if(flag)
                return ;
        }
    }
}
int main()
{
    while(cin>>n>>m>>t)
    {
        if(n==0&&m==0)
            break;
        int wall=0;
        for(int i=0; i<n; i++)
            for(int j=0; j<m; j++)
            {
                cin>>a[i][j];
                if(a[i][j]=='S')
                    sx=i,sy=j;
                else if(a[i][j]=='D')
                    ex=i,ey=j;
                else if(a[i][j]=='X')
                    wall++;
            }
        if(n*m-wall<=t)
        {
            cout<<"NO"<<endl;
            continue;
        }
        flag=false;
        a[sx][sy]='X';
        DFS(sx,sy,0);
        if(flag)
            cout<<"YES"<<endl;
        else
            cout<<"NO"<<endl;
    }
    return 0;
}



猜你喜欢

转载自blog.csdn.net/weixin_41863129/article/details/86515769