奇偶减支的使用

本文探讨了一道迷宫逃脱问题的深度优先搜索(DFS)算法优化策略。通过分析题目需求,逐步引入减支规则,包括时间限制、哈密顿距离预估和奇偶性检查,有效减少了搜索空间,避免了超时问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接。题目大意:给定迷宫的地图,起点S终点D和限制,D是一扇门,会在T时刻内打开,只有当D打开并且dog到达该点才能成功的逃脱,否则无法逃脱。给出相关的参数,判断dog是否可以逃脱。

看完之后发现这显然是一个dfs搜索的题目,我们当前点进行四个方向的搜索,判断步数和时间的关系即可。但是会发现程序超时,那么说明一个问题,我们的减支的力度不够,要从别的方面思考该如何进行减支。看到这个题和一般的题有一点小小的区别,一般的迷宫搜索都是在规定时间内出去即可,但是这里需要在准确的时间到达,因为题目中要求每一个点只能到达一次并且不能停留。所以在这里最短路不一定是最正确的选择。我们来思考dfs的减支

(1)T时刻内到达出口,递归结束

(2)T时刻内没有达到出口,递归也要结束

(3)小于T时刻内达到出口,这个时候没用,因为门没有开,所以也没用。

使用这三个减支的规则来减支,提交发现依然是超时。这个时候就开始怀疑人生了,难道这个题不是dfs?不会吧,显然是的啊。说明我们还有一些地方的减支没有考虑到。继续向下分析:这个题目很大的特点就是在迷宫中需要使用恰好T秒,不能多也不能少。那么其实我们可以发现一些二东西。假设出口D的坐标是在x,y当前的坐标点是在px,py.那么最少的时间肯定是两点之间的哈密顿距离。如果这时的时间已经不足,那么显然也是不能到达的,因为最短的时间已经不允许出去。OK,这个时候我们其实有得到了一个很重要的减支,其实我们在每一层的dfs都加一个这样的判断,那么就可以起到很大的作用。加上这个减支之后依然是超时,what?这nm还超,行吧,终极大招,奇偶减支。结合代码来说明:

#include <stdio.h>
#include <string.h>
#include <math.h>
char map[10][10]; //7*7
int book[10][10];
int p, q, n, m, t, flag;
int next[4][2] = { {0,1}, {1,0}, {0,-1}, {-1,0} }; //右下左上 
void dfs(int x, int y, int step) 
{
    //走的步数即等于时间 
    int i, tx, ty, temp;
    if (flag) return; //有一个方案成功及时结束 
    if (x == p && y == q) { //到达门 
        if (step == t) flag = 1;
        return;
    }
    if (step >= t) return; //!!!剪枝 超时或没走到 
    temp = t - step - abs(p - x) - abs(q - y);//这个
    if (temp < 0 || temp & 1) return;
    //剪枝:如果剩余的步数不足以走到出口,且必须是偶数,偶-偶=偶,奇-奇=偶
    for (i = 0; i < 4; i++)
    { //尝试4个方向 
        tx = x + next[i][0];
        ty = y + next[i][1]; //下一步的坐标
        if (tx<1 || tx>n || ty<1 || ty>m) //是否越界 
            continue;
        if (book[tx][ty] == 0 && map[tx][ty] != 'X')
        {
            book[tx][ty] = 1; //标记已走过 
            dfs(tx, ty, step + 1);
            if (flag) return; //有一个方案成功及时结束 
            book[tx][ty] = 0; //回溯 
        }
    }
    return;
}
int main() {
    int i, j, startx, starty, wall;
    while (scanf("%d%d%d", &n, &m, &t)) {
        getchar();
        if (n == 0 && m == 0 && t == 0) break;
        flag = wall = 0;
        for (i = 1; i <= n; i++) {
            for (j = 1; j <= m; j++)
            {
                map[i][j] = getchar();
                if (map[i][j] == 'S')
                {    //初始位置 
                    startx = i;
                    starty = j;
                }
                else if (map[i][j] == 'D') 
                { //门的位置 
                    p = i;
                    q = j;
                }
                else if (map[i][j] == 'X')
                    wall++;
            }
            getchar();
        }
        if (t > n*m - wall) printf("NO\n");
        //abs(p-startx)+abs(q-starty)为到达终点的最少步数 
        else if (abs(p - startx) + abs(q - starty) >= t && (startx + starty + p + q + t) % 2 == 1) printf("NO\n");
        //偶数点到偶数点(坐标xy之和)需要走偶数次,奇数到奇数也要走偶数次。 
        else 
        {
            memset(book, 0, sizeof(book)); //清零标记 
            book[startx][starty] = 1; //标记初始的占位 
            dfs(startx, starty, 0);
            if (flag) printf("YES\n");
            else printf("NO\n");
        }
    }
    return 0;
}
/*


这里回溯的原因:在搜索整个迷宫的时候,对于当前点:进行四个方向的搜索,dx=x+nex[i][j].假设这个点已经完成搜索
那么需要转移搜索中心,所以这里需要回溯
*/

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值