题目描述

解题思路
题解参考此处
代码
cpp
#include <bits/stdc++.h>
using namespace std;
const int N = 46; // k最大是25, 因此最多可能有2^25种方案
typedef long long ll;
int n, m, k, cnt, res;
int w[N], weights[1 << 25]; // weights存储能凑出来的所有的重量
// u表示当前枚举到哪个数了, s表示当前的和
void dfs1(int u, int s)
{
// 如果我们当前已经枚举完第k个数(下标从0开始的)了, 就把当前的s, 加到weights中去
if (u == k)
{
weights[cnt++] = s;
return;
}
// 枚举当前不选这个物品
dfs1(u + 1, s);
// 选这个物品, 做一个可行性剪枝(计算和的时候转成long long防止溢出)
if ((ll)s + w[u] <= m) dfs1(u + 1, s + w[u]);
}
void dfs2(int u, int s)
{
if (u >= n) // 如果已经找完了n个节点,二分找到答案(尽量大)
{
int l = 0, r = cnt - 1;
while (l < r)
{
int mid = l + r + 1 >> 1;
if (weights[mid] <= m - s) l = mid;
else r = mid - 1;
}
res = max(res, s + weights[l]);
return;
}
// 不选择当前这个物品
dfs2(u + 1, s);
// 选择当前这个物品
if ((ll)s + w[u] <= m) dfs2(u + 1, s + w[u]);
}
int main()
{
cin >> m >> n;
for (int i = 0; i < n; i++) cin >> w[i];
sort(w, w + n);
reverse(w, w + n); // 优化搜索顺序(从大到小)
k = n / 2 + 2; // 把前k个物品的重量打一个表(均衡复杂度,一般k=n/2)
dfs1(0, 0);
sort(weights, weights + cnt); // 做完之后, 把weights数组从小到大排序
cnt = unique(weights, weights + cnt) - weights; // 判重
// 从k开始, 当前的和是0
dfs2(k, 0);
cout << res;
return 0;
}
