HUD 1010-Tempter of the Bone(DFS+剪枝)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1010
题目大意:一只小狗被困在一个n*m的迷宫里,现在处在 ‘S’ 位置,判断其能否在 ‘T’ 秒是刚好到达出口 ‘D’,且走过的位置不能重复(这里要注意是刚好在 ‘T’ 时到达出口位置)

很明显这题应该用深搜来遍历,并且需要用到剪枝,不然面对指数级的遍历大概率会超时。但是令我没想到的时,这道题要剪很多次枝,要用到的最重要的就是奇偶性剪枝

这里简单的介绍下几次可以剪枝的地方:
:在数据输入后,可先判断所有剩余可走的格子数量是否大于时间T大小。这里可以先思考由于1秒走1步,所以 T秒正好到达出口 应该对应的就是 到出口一共要走T步所以小狗必须走慢T格,这个迷宫能走的位置内连T格都没有,因为走过的路就不能走了,那肯定不满足条件,直接筛掉。当然这一步只是粗略的判断,这一步无法筛去那些减去不连通(被墙挡住)的格子的数量小于T的情况。

if(n*m-1-x<T){     那些能走的格子还要排除‘S’,所以减1。
            cout<<"NO"<<endl;
            continue;
}

:如果DFS过程中当前步数以前超过T,但还没到,直接retrun;
:如果当前剩余T-cnt秒(步)能走,而T-cnt比 小狗离出口最短的距离 abs(X狗-X门)+abs(y狗-y门都小,说明肯定来不及。
:最关键的剪枝:奇偶性剪枝
先了解下它:
在这里插入图片描述
图片转自: https://blog.csdn.net/yinghui_yht/article/details/52971849

我们可以从上述结论中可以推理:如果 小狗离出口最短的距离 abs(X狗-X门)+abs(y狗-y门)
的距离为奇数,那么两个点肯定是 1-0 或者0-1的关系,又因为上述01or10奇数步结论,小狗不管怎么走走到出口这个距离肯定是奇数,剩余的步数T如果是偶数的话两者肯定不会相等,所以T必须为奇数。小狗离出口最短的距离 abs(X狗-X门)+abs(y狗-y门) 为偶数时反之。

简而言之:如果 小狗离出口最短的距离 abs(X狗-X门)+abs(y狗-y门) 为偶数,那么不管小狗怎么走肯定需要花偶数步来到达T;如果 小狗离出口最短的距离 abs(X狗-X门)+abs(y狗-y门) 为奇数,那么不管小狗怎么走肯定需要花奇数步来到达T。
因此我们这里可以直接来判断,并且结合 的技巧一起判断。

int temp=T-cnt-abs(x-d.x)-abs(y-d.y);   d.x和d.y即出口的坐标,x和y是小狗现在处在位置的坐标
if(temp&1||temp<0) return;

ACcode:

#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<map>
using namespace std;
struct node{
    int x,y;
};
node s,d;    s是小狗开始所在的位置,d是出口的位置
char maze[10][10];
int D[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
bool f;
int n,m,t;
void dfs(int x,int y,int cnt){
    if(cnt>t) return;			剪枝2
    int temp=t-cnt-abs(x-d.x)-abs(y-d.y);
    if(temp&1||temp<0) return;       剪枝34
    if(cnt==t&&x==d.x&&y==d.y){
        f=1;
        return;
    }
    node now;
    for(int i=0;i<4;i++){
        if(f) return;
        now.x=x+D[i][0];
        now.y=y+D[i][1];
        if(now.x<1||now.x>n||now.y<1||now.y>m||maze[now.x][now.y]=='X') continue;
        maze[now.x][now.y]='X';
        dfs(now.x,now.y,cnt+1);
        maze[now.x][now.y]='.';
    }
    return;
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    while(cin>>n>>m>>t,(n+m+t)){
        int x=0;
        f=0;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                cin>>maze[i][j];
                if(maze[i][j]=='S'){
                    s.x=i;
                    s.y=j;
                }
                if(maze[i][j]=='D'){
                    d.x=i;
                    d.y=j;
                }
                if(maze[i][j]=='X') x++;
            }
        }
        maze[s.x][s.y]='X';
        if(n*m-1-x<t){        剪枝1
            cout<<"NO"<<endl;
            continue;
        }
        dfs(s.x,s.y,0);
        if(f) cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值