在算法题中,"枚举所有可能" 是一种直观且有效的解题思路,但直接用数字表示状态或选项时,代码往往显得晦涩难懂。比如 "游游的礼盒" 这类问题,需要枚举礼盒中不同物品的组合并计算最大值,若用0、1、2代表物品,很容易混淆逻辑。今天我们就用 C++ 的强类型枚举(enum class) 来 "翻译" 枚举逻辑,让代码既安全又易读。
一、先看 "游游的礼盒" 问题:枚举所有组合求最大值
假设题目是这样的:游游有一个礼盒,里面可以放 3 件物品,每件物品只能是 "金币""宝石" 或 "药水",它们的分数分别是 2 分、5 分、3 分。求礼盒中 3 件物品的最大可能总分。
核心思路 :枚举 3 件物品的所有可能组合,计算每种组合的分数,取最大值。传统写法会用0、1、2代表三种物品,但用枚举类型能让代码 "说人话"。
二、用枚举类型 "翻译" 物品:从数字到语义
首先,用enum class定义物品类型,把抽象的数字 "翻译" 成具体的语义:
cpp
运行
cpp
// 用强类型枚举定义物品,每个枚举值对应一种物品
enum class Item {
Coin, // 金币,2分
Gem, // 宝石,5分
Potion // 药水,3分
};
这样一来,代码中不会再出现0、1、2,而是直接用Item::Coin"点名" 物品,可读性瞬间提升。
三、枚举所有组合:用枚举变量替代数字循环
接下来,我们需要枚举 3 件物品的所有可能组合。传统写法会用 3 层for循环遍历0-2,现在直接用枚举变量循环,配合显式转换控制范围:
cpp
运行
cpp
#include <iostream>
using namespace std;
// 定义物品枚举,显式指定底层类型为int,方便循环
enum class Item : int {
Coin, // 0
Gem, // 1
Potion, // 2
Count // 3,作为"哨兵值"标记枚举总数
};
// 根据物品类型获取分数
int getScore(Item item) {
switch (item) {
case Item::Coin: return 2;
case Item::Gem: return 5;
case Item::Potion: return 3;
default: return 0; // 不会触发,仅为编译通过
}
}
int main() {
int maxScore = 0;
// 枚举第一件物品:从Coin到Potion
for (int i = 0; i < static_cast<int>(Item::Count); ++i) {
Item item1 = static_cast<Item>(i);
// 枚举第二件物品
for (int j = 0; j < static_cast<int>(Item::Count); ++j) {
Item item2 = static_cast<Item>(j);
// 枚举第三件物品
for (int k = 0; k < static_cast<int>(Item::Count); ++k) {
Item item3 = static_cast<Item>(k);
// 计算当前组合分数
int current = getScore(item1) + getScore(item2) + getScore(item3);
// 更新最大值
if (current > maxScore) {
maxScore = current;
}
}
}
}
cout << "最大总分:" << maxScore << endl; // 输出15
return 0;
}
四、为什么用枚举类型更好?
对比传统的 "数字枚举",强类型枚举的优势一目了然:
1. 逻辑 "可视化",避免混淆
如果直接用数字,3 层循环的i、j、k代表什么?1+1+1又对应什么组合?而用Item::Gem,一眼就知道是 "宝石",Gem+Gem+Gem的组合逻辑清晰可见。
2. 强类型检查,减少 bug
如果不小心把Item::Coin写成4,编译器会直接报错;而传统数字枚举会默默接受错误值,导致逻辑漏洞。
3. 扩展性强,方便维护
如果题目新增 "钻石" 物品,只需在枚举中加一行Diamond,修改getScore函数即可,无需改动循环逻辑 ------ 因为循环依赖的是Item::Count这个 "哨兵值",自动适配枚举总数。
五、总结:枚举类型是算法的 "语义化工具"
在 "游游的礼盒" 这类枚举问题中,枚举类型的作用远不止 "给数字起名字",它更像一个 "语义化工具":把抽象的枚举逻辑 "翻译" 成人类能快速理解的语言,同时通过强类型检查保障代码正确性。
谢谢