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

      这是ACM之路学习的第一个算法——搜索算法。类似的题目有(HDOJ):1010、1240、1241、1242、1072、 1253、1312、1372(以上题目类似于1010)and 12381239、1015、1016、1401、1515、1548等。其中,1238不仅是基本搜索算法题,也是字符串处理的经典题目(包括求反串、求子串、字符串查找、求字符串长度),1239是数值型搜索题。而最经典的还属于1010题,该题的重点是涉及了两种剪枝方法,一是奇偶剪枝、一是路径剪枝。

     题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=1010

    dfs code:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <stdlib.h>
#include <cmath>
using namespace std;

const int MAXN = 10;
int n,m,t,sx,sy,dx,dy,wall;
char map[MAXN][MAXN];
int vis[MAXN][MAXN];
int flag;
int dir[4][2]={1,0,0,1,-1,0,0,-1};

int abs(int x){return x>0 ? x : -x;}

void DFS(int x,int y,int c){
    if(c>t) return ;//路径剪枝:超出时间则终止
    if(x<0 || y<0 || x>=n || y>=m) return ;//越界判断
    if(flag==1 || (map[x][y]=='D' && t==c)){//满足条件则返回
        flag=1;
        return ;
    }
    int temp =abs(x-dx)+abs(y-dy); //起点到终点的步数
    temp=t-temp-c; //剩余步数=时间-需要步数-已用时间时间
    if(temp<0 || temp&1) return ;//奇偶剪枝:走的步数是偶数,且剩余时间大于零,才会满足条件
    for(int i=0;i<4;++i){ //四个方向的搜索
        int tx=x+dir[i][0];
        int ty=y+dir[i][1];
        if(!vis[tx][ty] && map[tx][ty]!='X'){
            vis[tx][ty]=1;//走过就标记,防止再次访问
            DFS(tx,ty,c+1);
            vis[tx][ty]=0;//不满足条件则回溯,重新标记
        }
    }
}

int main(){
    //freopen("input.txt","r",stdin);
    while(~scanf("%d%d%d",&n,&m,&t) && (m||n||t)){
        wall=0;flag=0;//初始化
        memset(vis,0,sizeof(vis));//初始化
        for(int i=0;i<n;i++){
            scanf("%s",map+i);//接收迷宫
            for(int j=0;j<m;j++){
                if(map[i][j]=='S'){//标记迷宫入口
                    sx=i;sy=j;
                    vis[i][j]=1;
                }
                if(map[i][j]=='D'){//标记迷宫出口
                    dx=i;dy=j;
                }
                if(map[i][j]=='X')//迷宫墙计数,后边进行剪枝
                    wall++;
            }
        }
        if(n*m-wall-1>=t)//路径剪枝:当可以走的总数小于所给时间,则终止
            DFS(sx,sy,0);
        if(flag) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}

     更详细的版本 code:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <stdlib.h>
#include <cmath>
using namespace std;

const int MAXN = 10;
int n,m,t,sx,sy,dx,dy,wall;
char map[MAXN][MAXN];
int vis[MAXN][MAXN];
bool flag;

int abs(int x){return x>0 ? x : -x;}

void DFS(int i,int j,int c){
    if(c>t) return ;//路径剪枝:超出时间则终止
    if(i<0 || j<0 || i>=n || j>=m) return ;//越界判断
    if(flag==true || (map[i][j]=='D' && t==c)){//满足条件则返回
        flag=true;
        return ;
    }
    int temp =abs(i-dx)+abs(j-dy);//起点到终点的步数
    temp=t-temp-c;//剩余步数=时间-需要步数-已用时间时间
    if(temp<0 || temp&1) return ;//奇偶剪枝:走的步数是偶数,且剩余时间大于零,才会满足条件
    //map[i][j]='X';//走过就标记,防止再次访问
    if(!vis[i-1][j] && map[i-1][j]!='X'){
        vis[i-1][j]=true;//走过就标记,防止再次访问
        DFS(i-1,j,c+1);
       //if(flag) return ;
        vis[i-1][j]=false;//不满足条件则回溯,重新标记
    }
    if(!vis[i+1][j] && map[i+1][j]!='X'){
        vis[i+1][j]=true;//走过就标记,防止再次访问
        DFS(i+1,j,c+1);
        //if(flag) return ;
        vis[i+1][j]=false;//不满足条件则回溯,重新标记
    }
    if(!vis[i][j-1] && map[i][j-1]!='X'){
        vis[i][j-1]=true;//走过就标记,防止再次访问
        DFS(i,j-1,c+1);
        //if(flag) return ;
        vis[i][j-1]=false;//不满足条件则回溯,重新标记
    }
    if(!vis[i][j+1] && map[i][j+1]!='X'){
        vis[i][j+1]=true;//走过就标记,防止再次访问
        DFS(i,j+1,c+1);
        //if(flag) return ;
        vis[i][j+1]=false;//不满足条件则回溯,重新标记
    }
    //map[i][j]='.';//不满足条件则回溯,重新标记
    //直接对map[sx][sy]进行标记也可以,但在DFS各个方向的判断中加上if(flag) return ;
}

int main(){
    while(scanf("%d%d%d",&n,&m,&t)!=EOF && (m||n||t)){
        wall=0;flag=false;//初始化
        memset(vis,false,sizeof(vis));//初始化
        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                cin>>map[i][j];//接收迷宫
                if(map[i][j]=='S'){//标记迷宫入口
                    sx=i;sy=j;
                    vis[i][j]=true;
                }
                if(map[i][j]=='D'){//标记迷宫出口
                    dx=i;dy=j;
                }
                if(map[i][j]=='X')//迷宫墙计数,后边进行剪枝
                    wall++;
            }
        }
        if(n*m-wall-1>=t)//路径剪枝:当可以走的总数小于所给时间,则终止
            DFS(sx,sy,0);
        if(flag) 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、付费专栏及课程。

余额充值