#5316. 2026/3/7/LH笔记(二进制枚举+Map)
2026/3/7/LH笔记(二进制枚举+Map)
当前没有测试数据。
map容器 & 二进制枚举 课堂笔记
一、课前基础铺垫
1. 容器核心概念
C++容器是用于存储/管理数据的工具,本节课涉及两类核心容器:
vector:动态数组,大小可动态调整(本节课未实战,仅作为对比)map:键值对容器,可存储“键-值”对应关系(如姓名→学号)queue:队列容器(本节课仅声明未使用,暂不展开)
2. 进制转换基础(二进制枚举前置知识)
- 十进制转二进制:除2取余,逆序排列(不足指定位数补前导0)
- 二进制枚举核心:用十进制数的二进制表示“选/不选”状态(1=选,0=不选)
二、二进制枚举(解决组合/分组问题)
1. 核心用途
解决“从n个元素中选若干个”的组合问题(如:将数组分成两组,求两组和的最小差值)
2. 核心函数:tento(int x)(十进制转n位二进制字符串)
string tento(int x){
if (x == 0) return "0"; // 处理x=0的特殊情况
string ans = "";
while (x > 0){
int ys = x % 2; // 取余数(0/1)
ans = char(ys + '0') + ans; // 拼接二进制位(逆序拼接)
x /= 2; // 整除2,缩小x
}
while (ans.size() < n) ans = "0" + ans; // 补前导0,保证长度为n
return ans;
}
- 输入:十进制数
x(如x=13) - 输出:n位二进制字符串(如n=5时,输出"01101")
- 作用:将枚举的十进制数转为等长二进制串,方便对应“选/不选”状态
3. 主逻辑解析(数组分组求最小差值)
cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i], sum += a[i]; // 输入数组,求总和sum
for (int i = 1; i < pow(2, n); i++){ // 枚举1~2ⁿ-1(所有非空组合)
string s = tento(i); // 转二进制串
int tem = 0;
for (int j = 0; j < s.size(); j++){
if (s[j] == '1') tem += a[j + 1]; // 二进制位为1,选中对应元素
}
ans = min(ans, abs(sum - tem - tem)); // 计算两组差值(sum-tem为另一组和)
}
cout<<ans;
- 枚举范围:
1 ~ 2ⁿ - 1:避免全不选(i=0)的无效情况 - 差值计算:
abs(sum - 2*tem)(sum=选的和+没选的和 → 没选的和=sum-tem → 差值=|(sum-tem)-tem|) - 核心目标:遍历所有组合,找到最小差值
三、map容器(键值对容器)
1. 定义与本质
- 语法:
map<键类型, 值类型> 变量名 - 示例:
map<string, int> m;(键=字符串,值=整数) - 本质:存储“键-值”对,键唯一(不能重复),可通过键快速查找值
2. 核心操作(逐行解析)
| 操作 | 代码示例 | 详细说明 |
|---|---|---|
| 存储键值对 | m["Charlie"] = 1003; |
键为"Charlie",值为1003;若键已存在,会覆盖原有值 |
| 获取容器大小 | m.size(); |
返回map中键值对的数量(示例中初始存储3个,返回3) |
| 获取键对应的值 | m["Bob"]; |
返回键"Bob"对应的值(1002);若键不存在,会自动创建该键,值为类型默认值(int=0) |
| 检查键是否存在 | m.count("luohao"); |
返回1(存在)/0(不存在);不会创建新键,是检查键存在性的正确方式 |
| 遍历所有键值对 | for (auto [x, y] : m) |
x=键,y=值;遍历所有键值对(示例中会输出Alice 1001、Bob 1002、Charlie 1003) |
| 清空容器 | m.clear(); |
删除所有键值对,m.size()变为0 |
3. 关键特性
- 自动排序:map会按“键”的大小自动升序排列(字符串按字典序,数字按数值)
- 示例:存储顺序是Charlie→Bob→Alice,但遍历输出是Alice→Bob→Charlie
- 时间复杂度:单次访问/插入/查找的时间复杂度为
O(log n)(效率高于暴力遍历) - 易错点:直接用
m["不存在的键"]检查存在性会创建新键,导致m.size()增加(如m["luohao"]会新增键"luohao",值为0,size从3变4)
4. 遍历的另一种方式(迭代器,拓展)
// 兼容C++11之前的写法,与范围for等价
for (map<string, int>::iterator it = m.begin(); it != m.end(); it++) {
cout << it->first << " " << it->second << "\n"; // first=键,second=值
}
四、综合总结
核心知识点回顾
- 二进制枚举:通过十进制数的二进制表示枚举所有组合,核心是“位对应选/不选”,适用于n较小(n≤20)的组合/分组问题,
tento()函数是进制转换的核心工具; - map容器:键值对存储结构,查键存在性必须用
m.count(键)(避免自动创建新键),会按键自动排序,单次操作时间复杂度O(log n); - 核心易错点:直接访问map中不存在的键会自动创建该键,导致容器大小变化,务必用
count()检查键的存在性。