题目描述
约翰有一架用来称牛的体重的天平。与之配套的是 N (1≤N≤1000) 个已知质量的砝码(所有砝码质量的数值都在 32 位带符号整数范围内)。
每次称牛时,他都把某头奶牛安置在天平的某一边,然后往天平另一边加砝码,直到天平平衡,于是此时砝码的总质量就是牛的质量(约翰不能把砝码放到奶牛的那边,因为奶牛不喜欢称体重,每当约翰把砝码放到她的蹄子底下,她就会尝试把砝码踢到约翰脸上)。
天平能承受的物体的质量不是无限的,当天平某一边物体的质量大于 C (1≤C≤2^30) 时,天平就会被损坏。砝码按照它们质量的大小被排成一行。并且,这一行中从第 3 个砝码开始,每个砝码的质量至少等于前面两个砝码(也就是质量比它小的砝码中质量最大的两个)的质量的和。
约翰想知道,用他所拥有的这些砝码以及这架天平,能称出的质量最大是多少。由于天平的最大承重能力为 C,他不能把所有砝码都放到天平上。
现在约翰告诉你每个砝码的质量,以及天平能承受的最大质量,你的任务是选出一些砝码,使它们的质量和在不压坏天平的前提下是所有组合中最大的。
输入格式
第 1 行输入两个用空格隔开的正整数 N 和 C。
第 2 到 N+1 行:每一行仅包含一个正整数,即某个砝码的质量。保证这些砝码的质量是一个不下降序列。
输出格式
输出一个正整数,表示用所给的砝码能称出的不压坏天平的最大质量。
输入输出样例
输入 #1复制
3 15 1 10 20
输出 #1复制
11
#include <iostream>
using namespace std;
typedef long long ll;
ll n, c;
ll ans = 0;
ll a[1001], b[1001];
void dfs(int i, ll s) {
if (s > c) return; // 剪枝1: 砝码超重,直接返回
ans = max(ans, s); // 更新最大质量
if (i < 0) return; // 遍历结束
if (s + b[i] <= ans) return; // 剪枝2: 剩余质量不足
dfs(i - 1, s + a[i]); // 选择当前砝码
dfs(i - 1, s); // 不选择当前砝码
}
int main() {
cin >> n >> c;
for (int i = 0; i < n; i++) {
cin >> a[i];
}
b[0] = a[0];
for (int i = 1; i < n; i++) { // 计算前缀和 b[i],用于剪枝
b[i] = b[i - 1] + a[i];
}
dfs(n - 1, 0); // 从最后一个砝码开始搜索
cout << ans;
return 0;
}
剪枝:
if (s + b[i] <= ans) return;
b[i]
:从第 i
个砝码开始到最后的 所有砝码质量之和(前缀和)
如果当前质量 s
加上 所有剩余砝码的质量 b[i]
仍然小于等于 ans
,说明无论如何选择接下来的砝码,都不可能超过 ans
,那么继续递归就没有意义了,直接返回,避免无效计算。避免 TLE。