ZOJ:2110 Tempter of the Bone

简单回溯。

注意一点,标记该位置已访问要在各种不合理及边界终止条件之后,因为函数从这些地方跳出是不会将该位置改回未访问状态的,别的还好说,如果是终止位置,也就是'D'位置,将导致以后无法访问。总之标记访问状态的位置很重要,还有不要忘了结束的时候改成未访问状态。

 

 

在代码中加入了剪枝。

不剪枝要跑1s,剪枝以后大约400ms。

首先要意识到这么一个事情:从迷宫中的某一特定位置到另一个特定位置,不走重复路径,可以有多条路线,这些路线走的步数相差的步数是2的倍数。

也就是说如果从某点到D的最短距离小于要求走的步数而且相差值是2的倍数,那么是存在可能按要求到达D点的。否则不可能到达。

也就是说当某点到D的距离大于可走步数或者它们差值不是2的倍数这些情况可以剪掉。

 

另外可以在dfs开始前判一下如果X过多使得可走步数小于要求步数可以直接NO。

 

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
char grid[10][10];
int N,M,T,edx,edy;
bool vis[10][10];
bool ok;
void dfs(int I,int J,int D)
{

    if(ok) return;
    if(grid[I][J]=='X') return;
    if(!(1<=I&&I<=N&&1<=J&&J<=M))return;
    if(grid[I][J]=='D')
    {
        if(D==T) ok=true;
        return;
    }
    int tmp=(T-D)-(abs(I-edx)+abs(J-edy));
    if(tmp<0||tmp%2) return;
    vis[I][J]=true;
    if(!vis[I-1][J])  dfs(I-1,J,D+1);
    if(!vis[I][J-1])  dfs(I,J-1,D+1);
    if(!vis[I][J+1])  dfs(I,J+1,D+1);
    if(!vis[I+1][J])  dfs(I+1,J,D+1);
    vis[I][J]=false;
}
int main()
{
    while(scanf("%d%d%d",&N,&M,&T)&&!(!N&&!M&&!T))
    {
        memset(grid,0,sizeof(grid));
        memset(vis,false,sizeof(vis));
        getchar();
        int x,y;
        for(int i=1; i<=N; ++i)
        {
            for(int j=1; j<=M; ++j)
            {
                scanf("%c",&grid[i][j]);
                if(grid[i][j]=='S')
                {
                    x=i;
                    y=j;
                }
                else  if(grid[i][j]=='D')
                {
                    edx=i;
                    edy=j;
                }
            }
            getchar();
        }
        ok=false;
        dfs(x,y,0);
        if(ok) puts("YES");
        else puts("NO");
    }
    return 0;
}


 

你可能感兴趣的:(DFS,回溯,剪枝)