给出N个正整数组成的数组A,求能否从中选出若干个,使他们的和为K。如果可以,输出:"Yes",否则输出"No"。
Input
第1行:2个数N, K, N为数组的长度, K为需要判断的和(2 <= N <= 20,1 <= K <= 10^9)
第2 - N + 1行:每行1个数,对应数组的元素A[i] (1 <= A[i] <= 10^6)
Output
如果可以,输出:"Yes",否则输出"No"。
Input示例
5 13
2
4
6
8
10
Output示例
No
这道题我本来想的是全排列一下,然后分别取前1,2,3,...n 位,暴力求解,但是显然不行因为1,2 和 2,1结果一样。
这个想法可以优化,全排列是分别以 n个点 为起点去深搜,这里显然可以用一个点去深搜。
但是还是不行,因为1,3,2 和 1, 2, 3 结果是一样的, 还要再进行优化只从大于自身的点去深搜。
语言表达能力不太清楚,下面举个例子:
用 1, 2, 3, 4 去构成 10, 应该这样去深搜,深搜过程:
第一步 二 三 四 五
1 2 3 4
1 2 4
1 3 4
1 4
0 2 3 4
2 4
3 4
4
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 25;
int a[N]; // 存储数组
bool flag = 0;
// flag = 1 存在和为K的组合
int K;
void dfs(int k, int n, int ans) {
// n 为数组长度
if(ans == K){ // 存在和为K的组合
flag = 1;
}
if(flag || ans > K)
// 已找到存在解或 ans > n(ans只能增大),在搜素下去无意义
return ;
for(int i=k+1; i<=n && !flag; i++){
dfs(i, n, ans+a[i]);
}
}
int main()
{
int n;
cin >> n >> K;
for(int i=1; i<=n; i++) {
cin >> a[i];
}
flag = 0;
dfs(0, n, 0); // 开始搜索
if( flag )
cout << "Yes" << endl;
else
cout << "No" << endl;
return 0;
}