题解:学而思编程 vs怪物4

【题目来源】

题目来源:vs怪物4

【题目描述】

卡罗尔和 \(1\) 只怪物在战斗,这只怪物的体力是 \(H\)

卡罗尔每次可以对 \(1\) 只怪物发起攻击,此时有以下两种情况:

(1)如果被攻击的怪物的体力为 \(1\),那么这只怪物会被消灭。

(2)如果被攻击的怪物的体力 \(X>1\),那么这只怪物会被消灭,然后会出现两只体力为 \(⌊x/2⌋\) 的新的怪物。

\(⌊r⌋\) 表示不超过 \(r\) 的最大整数。

要消灭所有怪物,最少需要多少次攻击?

【输入】

\(1\) 行,\(1\) 个正整数 \(H\)

【输出】

输出消灭所有怪物最少需要进行的攻击次数

【输入样例】

2

【输出样例】

3

【核心思想】

  1. 问题分析:给定怪物初始体力 \(H\),每次攻击体力为 \(X\) 的怪物时:若 \(X=1\) 则直接消灭;若 \(X>1\) 则消灭后分裂为两只体力为 \(\lfloor X/2 \rfloor\) 的新怪物。求消灭所有怪物所需的最少攻击次数。这是一个递归分治问题,具有最优子结构和重叠子问题特性。

  2. 算法选择

    • 记忆化搜索(Memoization):使用递归 DFS 结合哈希表存储已计算结果,避免重复计算
    • 分治思想:将大问题分解为两个相同的子问题 \(f(\lfloor X/2 \rfloor)\)
  3. 关键步骤

    • 定义递归函数 \(dfs(x)\) 表示消灭体力为 \(x\) 的怪物所需最少攻击次数
    • 边界条件:若 \(x = 1\),返回 \(1\)(一次攻击即可消灭)
    • 记忆化检查:若 \(mp[x]\) 已存在,直接返回存储的结果
    • 递归计算\(dfs(x) = dfs(\lfloor x/2 \rfloor) + dfs(\lfloor x/2 \rfloor) + 1\)
      • 当前攻击 \(1\)
      • 加上消灭两只分裂怪物的攻击次数
    • 将结果存入 \(mp[x]\) 并返回
  4. 时间/空间复杂度

    • 时间复杂度:\(O(\log H)\),每次递归 \(x\) 变为 \(\lfloor x/2 \rfloor\),递归深度为 \(O(\log H)\),每层最多计算两个分支
    • 空间复杂度:\(O(\log H)\),递归栈深度和记忆化表大小均为 \(O(\log H)\)
  5. 记忆化搜索的核心思想

    • 重叠子问题:怪物分裂后产生的子问题可能重复出现(如 \(f(4)\)\(f(8)\) 都会计算 \(f(2)\)
    • 记忆化存储:使用哈希表 \(map\) 存储已计算的 \(f(x)\),避免重复递归
    • 自顶向下:从初始问题 \(f(H)\) 开始,递归分解为子问题
    • 适用于具有重叠子问题的递归问题,如斐波那契、树形 DP 等

【算法标签】

记忆化搜索

【代码详解】

#include <bits/stdc++.h>
using namespace std;
#define int long long
int h, ans;  // 初始高度h,答案ans
map<int, int> mp;  // 记忆化存储

int dfs(int x)  // 递归计算函数
{
    if (x==1) return 1;  // 边界条件:高度为1时返回1
    if (mp.count(x)) return mp[x];  // 如果已计算过,直接返回
    return mp[x] = dfs(x/2) + dfs(x/2) + 1;  // 递归计算
}

signed main()  // 主函数
{
    cin >> h;  // 输入初始高度
    cout << dfs(h);  // 输出结果
    return 0;  // 程序正常结束
}

【运行结果】

2
3
posted @ 2026-06-14 10:45  团爸讲算法  阅读(8)  评论(0)    收藏  举报