DFS剪枝初步

剪枝经典例题:
Tempter of the Bone http://acm.hdu.edu.cn/showproblem.php?pid=1010
题目描述: 一个迷宫有N*M格,有一些格子是地板能走,有一些格子是障碍不能走。给一个起点S和一个终点D。一只小狗从S出发,每步走一块地板,在每个地板不能停留,而且走过的地板都不能再走。给定一个T,问小狗能正好走T步到达D吗?
输入输出:有很多测试样例,每个测试中,第1行是整数N,M,T, 1 < N, M < 7, 0 < T < 50。后面有N行,每行M个字符,有这些字符:‘X’: 墙;‘S’: 起点;‘D’: 终点;’.’: 地板。最后一行是’0 0 0’,表示结束。如果狗能逃出,输出YES,否则输出NO。
输入输出样例:
输入
4 4 5
S.X.
…X.
…XD

3 4 5
S.X.
…X.
…D
0 0 0
输出
NO
YES。

题解:对于路径问题应该用DFS,对于这题采用奇偶剪枝。
奇偶方块图
曼哈顿距离f=abs(c−x)+abs(d−y),如果S和D的曼哈顿距离f是奇数,说明S和D一个是0一个是1;如果f是偶数,说明S和D同0或同1。对于此题,如果T−f是奇数则肯定无解,因为T和f必须同奇或同偶。
代码:

#include <bits/stdc++.h>
using namespace std;
char mat[8][8],visit[8][8];
int n, m, t;
int flag;           //flag=1,表示找到了答案
int a, b, c, d;     //起点S(a,b),终点D(c,d)
int dir[4][2] = {{1,0}, {-1,0}, {0,1}, {0,-1}};        //上下左右4个方向
#define CHECK(xx,yy) (xx>=0 && xx<n && yy>=0 && yy<m)  //是否在迷宫中

void dfs(int x, int y, int time){     
    if(flag)  return;                   //逐层退出DFS,有多少层DFS,就退多少次
    
    if(mat[x][y] == 'D'){        
        if(time == t)    flag = 1;      //找到答案
        return;                         //D只能走一次,所以不管对不对,都返回   
    }    
    //if(time > t)     return;          //剪枝(1):因为有剪枝(2),(1)就多余了

    int tmp = t - time - abs(c-x) - abs(d-y);
    if(tmp < 0)     return;             //剪枝(2)
    
    for(int i=0; i<4; i++){             //上下左右
        int xx = x + dir[i][0], yy = y + dir[i][1];
        if(CHECK(xx,yy)  && mat[xx][yy]!='X' && !visit[xx][yy]){      
            visit[xx][yy] = 1;          //地板标记为走过,不能再走        
            dfs(xx, yy, time + 1);      //遍历所有的路径
            visit[xx][yy] = 0;          //递归返回,这块地板恢复为没走过
        }
    }    
    return;
}
int main(){
    while(~scanf("%d%d%d",&n,&m,&t)){
        if(n==0 && m==0 && t==0)    break;
        for(int i=0;i<n;i++)
            for(int j=0;j<m;j++){
                cin>>mat[i][j];
                if(mat[i][j] == 'S') a=i,b=j;
                if(mat[i][j] == 'D') c=i,d=j;
            }
        memset(visit, 0, sizeof(visit));
        int tmp = t - abs(c-a) - abs(d-b);  //在DFS之前,做奇偶判断
        if(tmp & 1){                        //无解,不用DFS了
            puts("NO"); 
            continue;
        }
        flag = 0;
        visit[a][b] = 1;                    //标记起点已经走过
        dfs(a, b, 0);                       //搜索路径
        
        if(flag) puts("YES");
        else     puts("NO");
    }
    return 0;
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值