1. 题目背景与需求分析
"与怪物战斗"是一道经典的动态规划题目,常见于各大编程竞赛平台。题目描述通常为:玩家需要击败一系列怪物,每个怪物有特定的生命值和攻击力。玩家每次可以选择攻击一个怪物,但其他存活的怪物会同时攻击玩家。目标是找到最优的攻击顺序,使玩家受到的伤害总和最小。
这道题的核心在于理解动态规划中的状态转移过程。我们需要考虑的因素包括:
- 怪物的攻击顺序对总伤害的影响
- 剩余怪物的攻击力总和
- 已击败怪物与未击败怪物的状态关系
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 算法思路解析
2.1 动态规划状态定义
我们使用状态压缩DP来解决这个问题。定义dp[mask]表示击败mask表示的怪物集合时,玩家受到的最小总伤害。其中mask是一个二进制数,每一位表示对应怪物是否被击败(1表示已击败,0表示未击败)。
关键状态转移方程为:
dp[mask] = min(dp[mask], dp[mask^(1<<i)] + sum_attack * health[i])
其中:
- i是当前被击败的怪物索引
- sum_attack是所有未被击败怪物的攻击力总和
- health[i]是怪物i的生命值
2.2 时间复杂度分析
对于n个怪物,共有2^n种状态,每种状态需要遍历n个可能的转移,因此总时间复杂度为O(n*2^n)。这在n≤20时是可行的。
3. C++实现详解
3.1 数据结构设计
cpp复制struct Monster {
int health;
int attack;
};
3.2 核心算法实现
cpp复制int minTotalDamage(vector<Monster>& monsters) {
int n = monsters.size();
vector<int> dp(1 << n, INT_MAX);
dp[0] = 0;
for (int mask = 1; mask < (1 << n); ++mask) {
int sum_attack = 0;
for (int i = 0; i < n; ++i) {
if (!(mask & (1 << i))) {
