直接枚举三个不同位置的数字,检查三数和是否不超过 m,并维护最大的合法和。
OJ: luogu
题目 ID: P6437
难度:入门
标签:枚举模拟
日期: 2026-06-19 00:15
题意
给定 n 个正整数,从中恰好选出 3 个数。
要求这 3 个数的和不超过 m,并且在满足条件的前提下让这个和尽量大。
思路
先看一个可以直接验证想法的朴素解:
把“选 3 个数”当成搜索问题,用 DFS 枚举每个数选还是不选,直到正好选出 3 个数。
cpp
// brute.cpp:小数据暴力解,用来帮助理解题意并辅助对拍。
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 105;
int n, m;
int a[MAXN];
int ans;
void dfs(int idx, int cnt, int sum) {
if (cnt == 3) {
if (sum <= m) {
ans = max(ans, sum);
}
return;
}
if (idx > n) {
return;
}
// 选当前这个数。
dfs(idx + 1, cnt + 1, sum + a[idx]);
// 不选当前这个数。
dfs(idx + 1, cnt, sum);
}
void solve() {
ans = 0;
dfs(1, 0, 0);
cout << ans << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n >> m;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
solve();
return 0;
}不过本题的数据范围很小,n <= 100,其实没有必要写复杂搜索。
因为只需要选 3 个不同位置,所以直接枚举三元组就够了:
- 第一层枚举第一个位置
i - 第二层枚举第二个位置
j - 第三层枚举第三个位置
k
只要保证 i < j < k,就能把所有选法完整且不重复地枚举出来。
对每个三元组:
- 算出三数和
sum - 如果
sum <= m,就尝试更新答案
最后保留下来的最大合法和,就是题目要求的答案。
代码
cpp
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 105;
int n, m;
int a[MAXN];
void solve() {
int ans = 0;
for (int i = 1; i <= n; i++) {
for (int j = i + 1; j <= n; j++) {
for (int k = j + 1; k <= n; k++) {
int sum = a[i] + a[j] + a[k];
if (sum <= m) {
ans = max(ans, sum);
}
}
}
}
cout << ans << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n >> m;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
solve();
return 0;
}复杂度
时间复杂度是
总结
这题的重点不在优化,而在于看清数据范围。
当 n 只有 100 时,三重循环已经足够直接、稳定,也最容易写对。