【字符串处理、枚举T09】【DFS 深度优先搜索】解谜游戏

 

题目分析

  • 本题最优解必然满足所有按键最多只按下过一次,因为多次按压会抵消之前按压的效果;
  • 本题的最优解与按键顺序无关,因为所有灯的亮灭与按键是叠加关系,与先后顺序无关。

思路分享

本题是一道典型的枚举题,但如果我们对所有位置都进行遍历,我们最多需要考虑216*16种情况,这显然不满足题目要求,因此我们需要对算法进行优化。

经过观察,我们不难发现:当上一行以及之前所有行的状态都不改变时,上一行灯的亮灭状态只与本行的按键情况有关。因此,我们可以只遍历第一行灯的按键情况,后续每行只按压上一行还亮着的灯对应下方的按键,最后判断所有灯是否全部熄灭即可。

如何进行遍历

二进制方法

注意到本题中只有【按键】和【不按键】两种情况,故我们可以使用二进制数进行枚举,16位,每一位分别表示一个灯的亮灭情况,每次情况计算完成后加一即可。

DFS 深度优先搜索 方法

但是不是所有题目都能有这种简单的情形。考虑让题解的枚举方法具有普适性,此处我想讲解一种新的枚举方法:使用 DFS(深度优先搜索)进行枚举

我们想象所有的按键情况由一棵树组成,每一层对应一个灯的按键情况:

我们可以沿着某一条路径走到最底层【中止条件】(id = m),进行一次运算,统计出总的按键次数。接着,我们回溯到上一层,进行另一个抉择【回溯】,直到遍历完所有情况。算法的过程可以参考下图示意。

DFS有一套固定的流程如下:

void dfs(状态参数)
{
    if (达到中止条件 / 条件不合法)
    {
        添加相应内容
        return;
    }
    for (下一步所有的可行方法)
    {
        标记;
        dfs(参数进行相应改变);
        还原标记;
    }
}

对于本道题目,dfs部分的伪代码可以参考如下:

void dfs(灯的id, 按键次数)
{
    if (灯的id == m)
    {
        根据第一行状态推演所有按键次数;
        判断所有灯是否全部熄灭;
        更新最小按键次数;
        return;
    }

    // 第一种:按下的情况
    按下(第一行,第id个灯);
    dfs(id + 1, 按键数 + 1);
    按下(第一行,第id个灯); // 还原灯的状态

    // 第二种:不按下的情况
    dfs(id + 1, 按键数);
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值