题目大意:给定 n 个数字和一个正整数t ,要求在这n个数字中找出若干个数,使它们的和等于t ,然后输出所有这样的组合,注意输出的时候,严格地按照降序输出,即:每一行的所有数字降序输出,不同的行,先比较第一个数字,按降序输出;如果第一个数字相同,再按第二个数字降序输出,依次类推.
看完这道题,第一感觉就是"好像很难的样子,怎么做???",冷静下来后,开始思考自己做过的题目,觉得应该使用DFS,于是继续思考,按照DFS题目的标准步骤一步一步地思考,最终成功AC掉!
代码如下:
/*
* 既然已经确定采用DFS,那么:
* 第一步,设计DFS的参数有哪些: int len:当前已获得的数组的长度; int pos:本轮搜索的起始搜索位置; int sum: 当前已获得数组的和
* 第二步,设计DFS终止条件: if( sum == t ) output...
* 第三步 , 剪枝 , 此处的这个剪枝,比较难以理解,建议使用第一个case ,4 6 4 3 2 2 1 1,在纸上模拟DFS的执行流程,才会有比较透彻的理解
* BB一下,算法程序虽然短,但是它的思维量还是相当大的,不能偷懒,自己在草稿纸上进行模拟和推导对于理解算法有很大的帮助.
* AC : 172K 0 ms
*/
#include<iostream>
#include<stdio.h>
using namespace std;
// Data structure definition
int t , n ;
int a[14]; // 存储数字列表,如 4 , 3 , 2 , 2 , 1 , 1
int result[14]; // 存储结果数字列表,如 3 1
int succeed_flag; // 标识着是否找到解
void dfs( int len , int pos , int sum )
{
if( sum == t ) // 结束本次DFS,直接输出搜索到的数组 result[]
{
// 输出 result[]
for(int i=0;i<len;i++)
if( 0 == i )
printf("%d",result[i] );
else
printf("+%d",result[i] );
printf("\n");
succeed_flag = true;
return;
}
// 开始正式的DFS了,这部分是DFS的精髓所在
int pre_value = -1 ; // 记录已经搜索的值,防止重复性搜索
for(int i=pos;i<n;i++)
{
// 关键点:剪枝
if( (sum + a[i] <= t) && (a[i] != pre_value) ) // 剪枝,防止搜索到pre_value
{
pre_value = a[i];
result[ len ] = a[i];
// 开启下一级搜索
dfs( len + 1 , i + 1 , sum + a[i] );
}
}
}
int main()
{
int i,j,k;
while( scanf("%d%d",&t , &n ) != EOF && n !=0 )
{
succeed_flag = false;
for(i=0;i<n;i++)
scanf("%d",&a[i] );
printf("Sums of %d:\n",t );
dfs( 0 , 0 , 0 ); // 开启DFS搜索
if( false == succeed_flag )
printf("NONE\n");
}
return 0;
}