HDU 1010 -- Tempter of the Bone(dfs+奇偶剪枝)

题目大意:给出三个数,n,m,t,前两个数代表迷宫的大小,第三个数代表从迷宫入口到出口的时间,要求恰好在这个时间到达迷宫出口。

思路分析:因为不是求最短到达迷宫出口的时间,而是要求在固定的时间到达迷宫出口,也就是到达迷宫出口的路径不一定是最短的,所以不能用bfs,而是改用dfs,但是要注意剪枝,我就因为没有进行剪枝而超时了一次,这里使用的是奇偶剪枝,什么意思呢?

奇偶剪枝:

 
s    
|    
|    
|    
+e

我们假设s是起点,e是终点,‘|’代表竖着走,‘+’代表拐弯,‘-’代表横着走,图中就是s->e的最短路径,即min_step=abs(ex-sx)+abs(ey-sy)=8,在这道题中是偶数;
奇偶剪枝的核心思想就是我们所走的任何一条路径长度一定和min_step的奇偶性是一样的,可以自己画图试试看,给定时间t,也就相当于规定了所走路径的步数,也就是固定了路径,那么如果这条路径的奇偶性和min_step的奇偶是相同的,就说明这条路径是存在的,否则则说明这条路径是不存在的。
这道题我一共用奇偶剪枝两次:
第一次是在输入之后调用dfs之前,我们可以判断一下给定的时间t和最短路径长度的奇偶是否相同,如果不同,就说明我们没有办法在t时间到达出口,;
第二次是在进行dfs的过程中,我们走到任意一点(设为ss) ,把这个点当做起点,终点不变,此时的规定时间(设为tt)就相当于总规定时间减去到达这个点所用的时间,此时也就是判断从ss到终点存不存在一条步数为tt的路径,也就判断在ss到终点的最短距离和tt的奇偶性是否相同,如果相同,就说明存在步数为tt的这条路径,可以以这个点继续走下去,如果不相同,则说明这条路径不存在,不能以这个点当做起点走下去,无论哪个方向,直接返回这个点的上一个结点,这样也就直接减少了从这个点继续走下去的时间,减少大量不存在路径的判断,也就是我们奇偶剪枝的意义所在。

注意:每次走一个格,所以时间也就是路径的长度。

代码实现:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
char map[10][10];
int visit[10][10];
int n,m,t,flag,end_x,end_y,xi,yi;
int d[4][2]={-1,0,1,0,0,-1,0,1};
void dfs(int x,int y,int time){
    if(map[x][y]=='X'||visit[x][y]==1||x<0||x>=n||y<0||y>=m)
        return;
    if((abs(x-end_x)+abs(y-end_y))%2!=(t-time)%2) return;//第二次奇偶剪枝
    if(time>t) return;
    if(map[x][y]=='D'&&time==t){
        flag=1;
        return;
    }
    if(flag) return;
    visit[x][y]=1;
    for(int i=0;i<4;i++){
        dfs(x+d[i][0],y+d[i][1],time+1);
    }
    visit[x][y]=0;
}
int main(){
    while(~scanf("%d%d%d",&n,&m,&t),(n||m||t)){
        memset(visit,0,sizeof(visit));
        flag=0;
        for(int i=0;i<n;i++){
            scanf("%s",map[i]);
            for(int j=0;j<m;j++){
                if(map[i][j]=='S'){
                    xi=i;
                    yi=j;
                }
                if(map[i][j]=='D'){
                    end_x=i;
                    end_y=j;
                }
            }
        }
        if(t%2!=(abs(end_x-xi)+abs(end_y-yi))%2||t<(abs(end_x-xi)+abs(end_y-yi))){//第一次奇偶剪枝
            printf("NO\n");
            continue;
        }
        dfs(xi,yi,0);
        if(flag) printf("YES\n");
        else printf("NO\n");
    }
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值