菜鸟学算法之POJ 1564 Sum It Up

  题目大意:给定 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;
}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值