从0开始学算法——第十八天(分治算法练习)

写在开头的话

学习了今天的基础知识,让我们来做几道题来练练手吧。(题目是别的地方扒来的,参考答案是我自己写的,肯定不是最优解,有更好的方法欢迎评论区交流)

题目一------汉诺塔

题目二------情景题

题目三------蛋糕美味值

参考答案

第一题参考答案(Python版)

python 复制代码
def hanoi_tower(n, m, source, target, auxiliary, step_count, current_step):
    """
    n: 当前要移动的盘子数量
    m: 目标步数
    source: 源柱子
    target: 目标柱子
    auxiliary: 辅助柱子
    step_count: 当前已移动步数
    current_step: 当前步数的引用列表(用于记录当前步数)
    """
    if n == 0:
        return step_count
    
    # 移动n-1个盘子从source到auxiliary
    step_count = hanoi_tower(n-1, m, source, auxiliary, target, step_count, current_step)
    
    # 如果已经找到目标步数,直接返回
    if current_step[0] is not None:
        return step_count
    
    # 移动第n个盘子
    step_count += 1
    if step_count == m:
        current_step[0] = f"#{n}: {source}->{target}"
        return step_count
    
    # 移动n-1个盘子从auxiliary到target
    step_count = hanoi_tower(n-1, m, auxiliary, target, source, step_count, current_step)
    
    return step_count

def main():
    # 读取输入
    N, M = map(int, input().split())
    
    # 计算最少移动步数
    min_steps = 2**N - 1
    
    # 查找第M步的移动
    current_step = [None]
    total_steps = hanoi_tower(N, M, 'A', 'C', 'B', 0, current_step)
    
    # 输出结果
    if current_step[0]:
        print(current_step[0])
    else:
        print("#Invalid step")
    
    print(min_steps)

if __name__ == "__main__":
    main()

第二题参考答案(Python版)

python 复制代码
import sys
from functools import lru_cache

MOD = 998244353

def modinv(x: int) -> int:
    """返回x在模MOD下的逆元,MOD为质数"""
    return pow(x, MOD - 2, MOD)

def solve() -> None:
    data = sys.stdin.read().strip().split()
    if not data:
        return
    it = iter(data)
    n = int(next(it))
    k = int(next(it)) - 1          # 转为0-indexed
    a = [int(next(it)) for _ in range(n)]

    damages = [5, 4, 3, 2, 1]      # 依次造成的伤害值

    @lru_cache(maxsize=None)
    def dfs(i: int, state: tuple) -> int:
        """
        返回:从当前状态继续,最终第k个随从死亡的概率(模MOD)
        i: 已经完成了i次伤害 (0 <= i <= 5)
        state: 长度为n的元组,表示每个随从的当前血量(死亡则为0)
        """
        if i == 5:                 # 所有伤害完成
            return 1 if state[k] <= 0 else 0

        # 找出所有存活随从的索引
        alive = [idx for idx in range(n) if state[idx] > 0]
        if not alive:              # 没有存活随从,法术终止
            return 1 if state[k] <= 0 else 0

        d = damages[i]             # 本次伤害值
        m = len(alive)
        inv_m = modinv(m)          # 存活数的逆元
        res = 0
        for idx in alive:
            new_state = list(state)
            new_hp = state[idx] - d
            if new_hp < 0:
                new_hp = 0
            new_state[idx] = new_hp
            res = (res + dfs(i + 1, tuple(new_state))) % MOD
        res = res * inv_m % MOD
        return res

    ans = dfs(0, tuple(a))
    print(ans)

if __name__ == "__main__":
    solve()

第三题参考答案(Python版)

python 复制代码
def max_taste_sum():
    import sys
    
    # 读取输入
    data = sys.stdin.read().strip().split()
    n, k = map(int, data[:2])
    tastes = list(map(int, data[2:]))
    
    max_sum = 0
    
    # 使用位运算枚举所有子集
    for mask in range(1 << n):  # 枚举0到2^n-1
        current_sum = 0
        # 检查mask的每一位,如果为1则选择对应蛋糕
        for i in range(n):
            if mask & (1 << i):
                current_sum += tastes[i]
        
        # 如果当前和小于k且大于已知最大值,则更新
        if current_sum < k and current_sum > max_sum:
            max_sum = current_sum
    
    print(max_sum)

if __name__ == "__main__":
    max_taste_sum()
相关推荐
aqiu1111113 分钟前
【C++算法打怪专栏】LeetCode 402. 移掉 K 位数字(单调栈 + 贪心)
c++·算法·leetcode
FakeOccupational26 分钟前
【电路笔记 STM32】Cortex-M7 UART DMA模式(DMA&空闲中断&普通模式+DMA&半满/全满中断&循环模式)
笔记·stm32·嵌入式硬件
糖果豆豆29 分钟前
对象是字段,还是关系?集合论和范畴论吵了三十年,答案是两个都对
算法·架构
听风若依1 小时前
函数栈帧的创建与销毁-重置版
c语言·学习
第六种自由1 小时前
[路飞]_Leetcode 22. 括号生成
javascript·算法·leetcode
isyoungboy1 小时前
事件驱动状态机与循环扫描状态机:两种计算模型的比较研究
算法·状态机
行者全栈架构师1 小时前
【鸿蒙心迹】从手机到平板、折叠屏——多端适配自查清单与踩坑实录(HarmonyOS 7.x)
前端·算法·架构
Wang's Blog1 小时前
Java 项目部署之 Docker工具快速入门: 学习路径与命令速查导引
java·学习·docker
程序猿阿森1 小时前
Warmup 学习率预热详解:为什么训练初期要“先热身再加速”?
深度学习·学习·语言模型