题意:给你一个数字N,然后给你k,后面有k个数字,要用这k个数字凑出来最接近N但是不超过N的数字。
思路:我们直接搜索,传两个参数,一当前累加和,二当前选到了哪个数字。外面开一个标记数组,标记该数字有没有被选过。
全局维护一个最大值MAX,当MAX被更新时,我们把此时选择的数字存到ans数组里面。
为什么要传当前选到了哪个数字呢,这是一个剪枝,没有该剪枝会超时。当我们选到第二个数字的时候没必要再往前挑选数字了,因为第二个数字和第一个数字的组合一定在选择第一个数字的情况下包括。
题目好像说这些数字的大小在int范围内,但是用01背包能水过,估计是数据水把。
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 25;
int v, n, a[MAXN], ans[MAXN], MAX, cnt;
bool vis[MAXN];
void dfs(int sum, int r)
{
if (sum > MAX)
{
MAX = sum; cnt = 0;
for (int i = 0; i < n; i++)
{
if (vis[i]) ans[cnt++] = a[i];
}
}
for (int i = r; i < n; i++)
{
if (!vis[i] && sum + a[i] <= v)
{
vis[i] = true;
dfs(sum + a[i], i + 1);
vis[i] = false;
}
}
}
int main()
{
ios::sync_with_stdio(false);
while (cin >> v >> n)
{
memset(vis, 0, sizeof(vis));
MAX = 0;
for (int i = 0; i < n; i++) cin >> a[i];
dfs(0, 0);
long long t = 0;
for (int i = 0; i < cnt; i++)
{
printf("%d ", ans[i]);
t += ans[i];
}
printf("sum:%d\n", t);
}
return 0;
}
/*
5 3 1 3 4
10 4 9 8 4 2
20 4 10 5 7 4
90 8 10 23 1 2 3 4 5 7
45 8 4 10 44 43 12 9 8 2
*/