题目来源
挑战程序设计竞赛(第二版)
语言
C/C++
题目
部分和问题
描述
给定整数 a1, a2, ..., an,判断是否可以从中选出若干数,使它们的和恰好为 k。
样例1
输入:
n = 4
a = {1, 2, 4, 7};
k = 13
输出:
Yes
样例2
输入:
n = 4
a = {1, 2, 4, 7};
k = 15
输出:
No
思路
这道题目可以分解成两步,第一步先选取若干数,第二步对这些数进行求和判断是否等于 k。
以样例 1 为例,输入 4 个数,选取其中的若干数,求和,判断其和是否为 13。从头对这 4 个数进行依次访问,既然要选取若干数,那么每个数都有被选中或者弃选的可能(2 种情况),可以将整个选数的情况看做一棵二叉树,从根结点到叶子结点的路径就成为一组选数的可能。
(该图前两个数的情况)
只需要对这棵树进行遍历,每次遍历到叶子结点时判断一下当前的 sum 是否与 13 相等,若相等为找到一组数据,不相等继续遍历,若这棵树从头遍历一遍没有出现想要的结果,则判定无结果。
对这棵树进行遍历,我们可以使用深度优先搜索(DFS)。
代码
#include <iostream>
#define MAXBUF 256
int n = 4;
int k = 13;
int a[MAXBUF] = {1, 2, 4, 7};
bool dfs(int i, int sum);
int main(int argc, char *argv[]) {
using namespace std;
if (dfs(0, 0)){
cout << "Yes";
}
else
cout << "No";
return 0;
}
// i 为第 i 个数据 a[i-1],sum 为当前部分和
bool dfs(int i, int sum)
{
if (i == n){ // DFS 停止条件
return sum == k;
}
if (dfs(i + 1, sum)){ // 下个数据不加
return true;
}
if (dfs(i + 1, sum + a[i])){ // 下个数据加
return true;
}
return false; // 遍历所有结果都无符合条件
}
时间复杂度
对 n 个数进行遍历,每个数都有 2 种情况,因此时间复杂度为 O(2^n)。
所涉及的知识点
深度优先搜索(DFS)