解题思路:
从这道题的数据范围来看,n最大30,如果暴力枚举,时间复杂度为2的30次方,绝对会超时的,这时候我们应该想别的办法。
之前我写过一种背包的方法:
何以包邮? csp 202209-2(回溯70分+DP100分)_何以包邮?_星河边采花的博客-CSDN博客
现在介绍一种双向dfs做法:
因为n最大为30,dfs会超时,所以我们可以将n个数分为两组,左边一组直接做dfs,右边一组做dfs后和左边的进行组合,来更新结果。具体思路可以看b站的那次讲解:
第27次CCF CSP认证题目精讲直播回放_哔哩哔哩_bilibili
这里给上代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 35;
int n, m, k;
int weights[1 << 16],cnt;
int w[N];
int res = 1e9;
void dfs1(int u, int sum) {
if (u == k) {
weights[cnt++] = sum;
return;
}
dfs1(u + 1, sum);
dfs1(u + 1, sum + w[u]);
}
void dfs2(int u, int sum) {
if (u == n) {
int l = 0, r = cnt;
while (l < r) {
int mid = l + r>> 1;
if (sum + weights[mid] >= m)r = mid;
else l = mid + 1;
}
if (sum + weights[l] >= m)res = min(res, sum + weights[l]);
return;
}
dfs2(u + 1, sum);
dfs2(u + 1, sum + w[u]);
}
int main() {
//输入数据
scanf("%d%d", &n, &m);
for (int i = 0; i < n; i++)scanf("%d", &w[i]);
//剪枝,先枚举大的,可以更快接近答案
sort(w, w + n);
reverse(w, w + n);
//先dfs左边一半的数据
k = n / 2;
dfs1(0, 0);
//将得到的结果排序,去重,留着一会遍历右边一半数据时,在这个数组中二分查找
sort(weights, weights + cnt);
cnt = unique(weights, weights + cnt) - weights;
//dfs右边一半数据
dfs2(k, 0);
//输出结果
printf("%d", res);
}