题解:AtCoder AT_awc0062_c Optimal Menu Selection for an Izakaya
【题目来源】
AtCoder:C - Optimal Menu Selection for an Izakaya
【题目描述】
Takahashi is at an izakaya (Japanese-style pub). The menu has \(N\) dishes, and the \(i\)-th dish has a "deliciousness" value \(A_i\) and a "richness" value \(B_i\). Takahashi can order any combination of these dishes. Each dish can be ordered at most once, and it is also allowed to order no dishes at all (in which case, the satisfaction is \(0\)).
高桥在一家居酒屋。菜单上有 \(N\) 道菜,第 \(i\) 道菜有一个"美味度"值 \(A_i\) 和一个"浓郁度"值 \(B_i\)。高桥可以点任意组合的这些菜。每道菜最多点一次,也可以不点任何菜(此时满意度为 \(0\))。
Takahashi likes rich dishes, but if the total richness of the ordered dishes exceeds \(K\), his satisfaction decreases by \(D\) for each unit of excess richness.
高桥喜欢浓郁的菜,但如果所点菜品的总浓郁度超过 \(K\),他的满意度会降低,每超出 \(1\) 单位扣除 \(D\) 的满意度。
Specifically, Takahashi's final satisfaction is calculated by the following formula:
具体来说,高桥的最终满意度由以下公式计算:
\(\text{Satisfaction} = \left(\text{Total deliciousness of ordered dishes}\right) - D \times \max\!\left(0,\ \text{Total richness of ordered dishes} - K\right)\)
\(\text{满意度} = \left(\text{所点菜品的美味度总和}\right) - D \times \max\!\left(0,\ \text{所点菜品的总浓郁度} - K\right)\)
Find the maximum satisfaction Takahashi can achieve.
求高桥能获得的最大满意度。
【输入】
\(N\) \(K\) \(D\)
\(A_1\) \(B_1\)
\(A_2\) \(B_2\)
\(\vdots\)
\(A_N\) \(B_N\)
- The first line contains the number of dishes \(N\), the richness tolerance limit \(K\), and the satisfaction decrease per unit of excess \(D\), separated by spaces.
- From the 2nd line to the \((N+1)\)-th line, the deliciousness and richness of each dish are given.
- The \((1+i)\)-th line contains the deliciousness \(A_i\) and richness \(B_i\) of the \(i\)-th dish, separated by a space.
【输出】
Print the maximum satisfaction Takahashi can achieve as an integer on a single line.
【输入样例】
3 5 2
4 2
5 3
10 6
【输出样例】
9
【核心思想】
-
问题分析:给定 \(N\) 道菜,每道菜有美味度 \(A_i\) 和浓郁度 \(B_i\)。高桥可以点任意子集的菜(每道最多一次),满意度为所点菜品的总美味度减去超出浓郁度限制 \(K\) 的部分乘以惩罚系数 \(D\)。求最大满意度。由于 \(N \leq 20\),总子集数为 \(2^N \leq 10^6\),可以直接枚举所有子集求解。这是一个子集枚举(状压 DP)问题。
-
算法选择:
- 子集枚举(Bitmask Enumeration):用二进制数 \(mask\) 表示菜品选择状态,第 \(i\) 位为 \(1\) 表示选择第 \(i\) 道菜
- 递推预处理:利用 lowbit 技巧,\(sum[mask] = sum[\text{prevMask}] + \text{该位值}\),在 \(O(2^N)\) 时间内预处理所有子集的和
-
关键步骤:
- 读取输入:\(N\)、\(K\)、\(D\),以及每道菜的 \(A_i\) 和 \(B_i\)
- 预处理子集和:
- 枚举 \(mask\) 从 \(1\) 到 \(2^N - 1\)
lsb=__builtin_ctz(mask):获取最低位的索引prevMask= \(mask \oplus (1 \ll lsb)\):去掉最低位- \(sumA[mask] = sumA[prevMask] + A_{lsb+1}\),\(sumB[mask] = sumB[prevMask] + B_{lsb+1}\)
- 枚举计算满意度:
- 遍历所有 \(mask \in [0, 2^N)\)
- 满意度 = \(sumA[mask] - D \times \max(0, sumB[mask] - K)\)
- 更新全局最大值
- 输出答案
-
时间/空间复杂度:
- 时间复杂度:\(O(2^N)\),预处理子集和与枚举各需一次 \(2^N\) 遍历
- 空间复杂度:\(O(2^N)\),存储两个子集和数组
-
状压 DP 的核心思想:
- 状态压缩:将集合选择状态压缩为一个整数(二进制位),使子集操作转化为位运算,极大简化代码
- 递推求子集和:利用子集包含关系,\(mask\) 的和可由去掉一个元素的子集转移而来,避免重复计算,实现 \(O(2^N)\) 预处理
- 适用规模:\(N \leq 20 \sim 22\) 时 \(2^N\) 可接受;\(N > 25\) 时需考虑其他算法(如折半搜索、DP 优化)
- 适用于小规模集合的最优子集选择、子集计数、子集覆盖等问题
【算法标签】
状压DP
【代码详解】
#include <bits/stdc++.h>
using namespace std;
#define int long long // 将int定义为long long类型
const int N = 25, M = 1 << 20; // N:最大物品数(25), M:最大子集数(2^20)
int n; // 物品数量
int k; // 脂肪标准值
int d; // 脂肪惩罚系数
int ans; // 最大满意度
int a[N]; // 存储每个物品的美味值
int b[N]; // 存储每个物品的脂肪值
int suma[M]; // 子集的美味值总和
int sumb[M]; // 子集的脂肪值总和
signed main() // 因为使用了#define int long long,所以用signed
{
cin >> n >> k >> d; // 输入物品数量、脂肪标准值、惩罚系数
// 输入每个物品的美味值和脂肪值
for (int i = 1; i <= n; i++)
{
cin >> a[i] >> b[i];
}
// 预处理:计算所有子集的美味值总和和脂肪值总和
for (int mask = 1; mask < (1 << n); mask++) // mask表示物品子集
{
int lsb = __builtin_ctz(mask); // 获取mask的最低有效位(从0开始)
int prevMask = mask ^ (1 << lsb); // 去掉最低有效位
suma[mask] = suma[prevMask] + a[lsb + 1]; // 计算美味值总和
sumb[mask] = sumb[prevMask] + b[lsb + 1]; // 计算脂肪值总和
}
// 遍历所有子集,计算最大满意度
for (int mask = 0; mask < (1 << n); mask++)
{
int delicious = suma[mask]; // 当前子集的美味值总和
int rich = sumb[mask]; // 当前子集的脂肪值总和
// 计算满意度:美味值总和 - 脂肪惩罚
int satisfaction = delicious - d * max(0LL, rich - k);
ans = max(ans, satisfaction); // 更新最大满意度
}
cout << ans << endl; // 输出最大满意度
return 0; // 程序正常结束
}
【运行结果】
3 5 2
4 2
5 3
10 6
9
浙公网安备 33010602011771号