竞赛基础篇---部分和问题(DFS)
问题链接:http://acm.nyist.edu.cn/JudgeOnline/problem.php?pid=1058
- 描述
- 给定整数a1、a2、.......an,判断是否可以从中选出若干数,使它们的和恰好为K。
- 输入
- 首先,n和k,n表示数的个数,k表示数的和。
接着一行n个数。
(1<=n<=20,保证不超int范围) - 输出
- 如果和恰好可以为k,输出“YES”,并按输入顺序依次输出是由哪几个数的和组成,否则“NO”
- 样例输入
-
4 13 1 2 4 7
- 样例输出
-
YES 2 4 7
- 思路:
- 直接dfs,每次dfs用两个参数,一个为当前层数,一个为当前以及凑出的总和。这里可以剪枝:如果当前凑出的总和 > k,直接返回false;
- 此处还应该记录每个数字是否被标记,这里需要注意,一定要在返回真之后再加标记,因为只有返回真,才能确定该点的标记状态
1 #include<iostream> 2 #include<string> 3 #include<vector> 4 #include<cstdio> 5 #include<cstring> 6 #define FOR(i, a, b) for(int i = a; i < b; i++) 7 using namespace std; 8 int n, k; 9 int a[50], vis[50]; 10 bool dfs(int d, int tot) 11 { 12 if(tot > k)return false; 13 if(d == n)return tot == k;//到了最后一层,直接返回判断结果 14 //如果第i层不放a[i] 15 if(dfs(d + 1, tot)) 16 { 17 vis[d] = 0;//标记未放 18 return true; 19 } 20 //如果第i层放a[i] 21 if(dfs(d + 1, tot + a[d])) 22 { 23 vis[d] = 1;//标记已放 24 return true; 25 } 26 return false; 27 } 28 int main() 29 { 30 while(cin >> n >> k){ 31 for(int i = 0; i < n; i++) 32 { 33 cin >> a[i]; 34 } 35 if(dfs(0, 0)) 36 { 37 printf("YES\n"); 38 for(int i = 0; i < n; i++)if(vis[i])printf("%d ", a[i]); 39 printf("\n"); 40 } 41 else 42 printf("NO\n"); 43 } 44 return 0; 45 }
越努力,越幸运