从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()
相关推荐
qianpeng8977 小时前
水声匹配场定位原理及实验
算法
tingshuo291718 小时前
S001 【模板】从前缀函数到KMP应用 字符串匹配 字符串周期
笔记
董董灿是个攻城狮19 小时前
AI视觉连载8:传统 CV 之边缘检测
算法
AI软著研究员1 天前
程序员必看:软著不是“面子工程”,是代码的“法律保险”
算法
FunnySaltyFish1 天前
什么?Compose 把 GapBuffer 换成了 LinkBuffer?
算法·kotlin·android jetpack
颜酱1 天前
理解二叉树最近公共祖先(LCA):从基础到变种解析
javascript·后端·算法
地平线开发者2 天前
SparseDrive 模型导出与性能优化实战
算法·自动驾驶
董董灿是个攻城狮2 天前
大模型连载2:初步认识 tokenizer 的过程
算法
地平线开发者2 天前
地平线 VP 接口工程实践(一):hbVPRoiResize 接口功能、使用约束与典型问题总结
算法·自动驾驶
罗西的思考2 天前
AI Agent框架探秘:拆解 OpenHands(10)--- Runtime
人工智能·算法·机器学习