HDU 1010 搜索+剪枝

http://acm.hdu.edu.cn/showproblem.php?pid=1010

题目大意:这道题就是讲有一只狗要吃骨头,结果进入了一个迷宫陷阱,迷宫里每走过一个地板费时一秒,该地板就会在下一秒塌陷,所以你不能在该地板上逗留。迷宫里面有一个门,只能在特定的某一秒才能打开,让狗逃出去。现在题目告诉你迷宫的大小和门打开的时间,问你狗可不可以逃出去,可以就输出YES,否则NO。

解题思路:这道题,要用到剪枝搜索来做,否则会超时。剪掉的条件是,如果可走地板数目小于给定的时间,绝对不可能得救。还有就是狗走到门的时间必须和题目给定的时间是同奇同偶的,否则也不能在指定的那秒到达门,也不可能得救,剪掉这两种情况后。就用深度搜索来做。从起点出发,深搜周围的路,走过的路就标记为不可走,一直搜索下去,如果搜索失败就回溯,恢复原数据,把可能的路都搜索一遍过去,看看是否有可行方案。

关于剪枝,没有剪枝的搜索不太可能,一个是奇偶剪枝,一个是路径剪枝

奇偶剪枝:
把矩阵标记成如下形式:
0,1,0,1,0
1,0,1,0,1
0,1,0,1,0
1,0,1,0,1
很明显,如果起点在0 而终点在1 那显然 要经过奇数步才能从起点走到终点,依次类推,奇偶相同的偶数步,奇偶不同的奇数步
在读入数据的时候就可以判断,并且做剪枝,当然做的时候并不要求把整个矩阵0,1刷一遍,读入的时候起点记为(Si,Sj) 终点记为(Di,Dj) 判断(Si+Sj) 和 (Di+Dj) 的奇偶性就可以了

路径剪枝:
矩阵的大小是N*M 墙的数量记为num 如果能走的路的数量 N*M - num 小于时间T,就是说走完也不能到总的时间的,这显然是错误的,可以直接跳出了

剪枝3:就是记录当前点到终点的最短路,如果小于剩余的时间的话,就跳出

代码:

#include<stdio.h>
#include<math.h>
#include<string.h>
#define N 10
int dir[4][2]={-1,0,1,0,0,-1,0,1};
int flag,di,dj,T,m,n;
char str[N][N];
void dfs(int si,int sj,int t)
{
    int i,temp;
    if(si==di&&sj==dj&&t==T)
    {
        flag=1;
        return ;
    }
    if(si<0||si>=m||sj<0||sj>=n)
        return ;
    temp=T-t-abs(si-di)-abs(sj-dj);
    if(temp<0||temp%2!=0)        //奇偶剪枝,剪枝3
        return ;
    for(i=0;i<4;i++)
    {
  //千万要注意的是节点越界的情况, dfs(int si,int sj,int t)的时候一定要把 si, sj 控制在给你的矩阵内
        if(si+dir[i][0]>=0&&si+dir[i][0]<m&&sj+dir[i][1]>=0&&sj+dir[i][1]<n)
        if(str[si+dir[i][0]][sj+dir[i][1]]!='X')
        {
            str[si+dir[i][0]][sj+dir[i][1]]='X';
            dfs(si+dir[i][0],sj+dir[i][1],t+1);
            if(flag)  return ;
            str[si+dir[i][0]][sj+dir[i][1]]='.';    //搜索失败,恢复原数据
        }
    }
    return ;
}
int main()
{
    int i,j,si,sj,t,num;
    while(scanf("%d%d%d",&m,&n,&T)!=EOF)
    {
        getchar();
        if(m==0&&n==0&&T==0)
            break;
        num=0;
        for(i=0;i<m;i++)
        {
            for(j=0;j<n;j++)
            {
                scanf("%c",&str[i][j]);
                if(str[i][j]=='S')
                {
                    si=i;sj=j;
                }
                else if(str[i][j]=='D')
                {
                    di=i;dj=j;
                }
                else if(str[i][j]=='X')
                    num++;
            }
            getchar();
        }
        if(m*n-num<=T)      //路径剪枝
        {
            printf("NO\n");
            continue;
        }
        flag=0;
        str[si][sj]='X';
        dfs(si,sj,0);
        if(flag)
            printf("YES\n");
        else
            printf("NO\n");
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值