zoj 2110 dfs,剪枝

链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1110

题意:从起点走到目的地,不能回退到走过的格子,S表示起点,D表示终点,X表示墙,’ . ’表示空格,求在规定时间t内,能否到达终点。n,m表示迷宫的长和宽。

思路:dfs,从起点开始搜,每个格子有四个方向,一个一个地搜。每搜一个格子,就要把格子设为X,因为不能走重复的格子,遇到墙壁或者边界就走不动,走不动就回退,要把格子恢复为‘ . ’,回到上一步的情况。如果某个位置满足条件,就停止搜索。如果全部分支都搜索完了还找不到解,就无解。

其中有两处剪枝,一处是在主函数中,如果空格子数小于等于时间t,那么肯定无解。另一处是在dfs函数中,temp为当前剩余时间与到终点所要花的最短时间的差,如果为负或者是奇数就肯定不能成功。因为如果是奇数的话,就不满足那个,嗯,只能意会不能言传。。。

#include<cstdio>
#include<cmath>
int n,m,t;
int di,dj;
int escape;
char map[8][8];
int dir[4][2]={{0,-1},{0,1},{1,0},{-1,0}};
void dfs(int si,int sj,int cnt)
{
    if(si>=n||sj>=m||si<0||sj<0) return;
    if(si==di && sj==dj &&cnt==t)
    {
        escape=1;
        return;
    }
    int temp=(t-cnt)-fabs(si-di)-fabs(sj-dj);
    if(temp<0 || temp%2!=0) return;//剪枝
    for(int i=0;i<4;i++)
        if(map[si+dir[i][0]][sj+dir[i][1]] != 'X')
        {
            map[si+dir[i][0]][sj+dir[i][1]]='X';
            dfs(si+dir[i][0],sj+dir[i][1],cnt+1);
            if(escape) return;
            else map[si+dir[i][0]][sj+dir[i][1]]='.';
        }
    return;
}
int main()
{
    int si,sj;
    int wall;
    while(scanf("%d%d%d",&n,&m,&t) &&n&&m&&t)
    {
        getchar();
        wall=0;
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<m;j++)
            {
                scanf("%c",&map[i][j]);
                if(map[i][j]=='S')
                {
                    si=i;
                    sj=j;
                }
                else if(map[i][j]=='D')
                {
                    di=i;
                    dj=j;
                }
                else if(map[i][j]=='X')
                    wall++;
            }
            getchar();
        }
        if(n*m-wall<=t)//剪枝
           printf("NO\n");
        else
        {
           escape=0;
           map[si][sj]='X';
           dfs(si,sj,0);
           if(escape) printf("YES\n");
           else printf("NO\n");
        }
    }

    return 0;
}
原文地址:https://www.cnblogs.com/54zyq/p/3072574.html