【字符串处理、枚举T09】【DFS 深度优先搜索】解谜游戏
本文最后更新于 311 天前,其中的信息可能已经有所发展或是发生改变。

题目分析

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

思路分享

本题是一道典型的枚举题,但如果我们对所有位置都进行遍历,我们最多需要考虑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, 按键数);
}


欢迎通过E-mail:blog#drinkcat.com 与我进行交流。
关注我的微信订阅号:饮猫DrinkCat在BIT,即是对我最大的支持~


暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇