HDOJ(HDU).1258 Sum It Up (DFS) [从零开始DFS(6)]

点我挑战题目

从零开始DFS

HDOJ.1342 Lotto [从零开始DFS(0)] — DFS思想与框架/双重DFS

HDOJ.1010 Tempter of the Bone [从零开始DFS(1)] —DFS四向搜索/奇偶剪枝

HDOJ(HDU).1015 Safecracker [从零开始DFS(2)] —DFS四向搜索变种

HDOJ(HDU).1016 Prime Ring Problem (DFS) [从零开始DFS(3)] —小结:做DFS题目的关注点

HDOJ(HDU).1035 Robot Motion [从零开始DFS(4)]—DFS题目练习

HDOJ(HDU).1241 Oil Deposits(DFS) [从零开始DFS(5)] —DFS八向搜索/双重for循环遍历

HDOJ(HDU).1258 Sum It Up (DFS) [从零开始DFS(6)] —DFS双重搜索/去重技巧

HDOJ(HDU).1045 Fire Net [从零开始DFS(7)]—DFS练习/check函数的思想

题意分析

每组数据给出要凑出的目标数字num和数字个数n,然后依次给出n个数字。要求从n个数字中选出若干个数字,是的数字之和为nun。重复的组合只输出一次。

和之前做过的选数字的题目类似,也可以采用DFS的思想来做。这道题与HDOJ.1342 Lotto [从零开始DFS(0)]及其的相似:每个数字有2种选择,选/不选,只要我选择的这些数字的和为num就行了。但是不难想到会有重复的组合出现,例如给出的样例3:

400 12 50 50 50 50 50 50 25 25 25 25 25 25

要求从12个数字中选择出若干数字使得总和为400,我们可以发现选择6个50和4个25即可。那么若按照HDOJ.1342的思想,选/不选,问题就会出现:要从6个25中选4个25,会有C(6,4)中情况,也就是说最后的结果会多出11组相同的解。这显然不符合题意。

问题的关键在于如何去重,最先想到也是最容易想到的就是把每组解保存下来,如果遇到重复的只输出一组即可。很明显这种方法实现起来耗费的工程量是巨大的,非常麻烦。回到DFS的核心:递归。我们对于递归做出一些约束,当满足一定条件时,下面搜索的解会造成重复,就终止递归。这样得到的解,均是非重复的。关键就是找到这样的条件,或者说为递归创造这样的条件。

上代码。

代码总览

/*
Title:HDOJ.1258
Author:pengwill
Date:2017-2-8
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int num,n,pos;
int a[15],b[15];
bool judge = false;
void output(int depth)
{
for(int i =0 ;i< depth; ++i)
if(!i) printf("%d",b[i]);
else printf("+%d",b[i]);
printf("\n");
}
void dfs(int depth,int sum,int pos)
{
if(sum == num) {judge = true;output(depth); return;}
if(sum>num) return;// 超出了 终止递归
if(pos>=n) return; //选择的数的位置超出数据范围
b[depth] = a[pos];
dfs(depth+1,sum+a[pos],pos+1);
while(pos+1<n&&a[pos] == a[pos+1]) pos++;//关键
dfs(depth,sum,pos+1); }
int main()
{
//freopen("in.txt","r",stdin);
while(scanf("%d%d",&num,&n) && num){
printf("Sums of %d:\n",num);
for(int i = 0; i<n; ++i) scanf("%d",&a[i]);
judge = false;
dfs(0,0,0);
//output
if(judge == false) printf("NONE\n");
}
return 0;
}

还是按照HDOJ.1342 Lotto [从零开始DFS(0)]中写到的双重DFS的办法(即选/不选的思想),解决此题。

递归边界:当数字的和为num时,或者和超出了num,或者要选择的数字位置超出了n,终止搜索。

关键是下面这几句。

    dfs(depth+1,sum+a[pos],pos+1);
while(pos+1<n&&a[pos] == a[pos+1]) pos++;//关键
dfs(depth,sum,pos+1);

首先是默认选择了pos这个位置的数字然后进行dfs。下面一个while循环表示如果下一个待选数字和本位置的待选数字一样的话,就跳过,一直跳到下一个待选数字不同的位置。如样例3:

400 12 50 50 50 50 50 50 25 25 25 25 25 25

就会从第一个50一直跳到最后一个50(下一个数字是25)。貌似看起来得不到正确结果,当然在第一层dfs不选择50的情况是没有正确解的。不放我们看一下下一层dfs,即选择了第一个50后的dfs。

进入第二层dfs依旧会有2种选择,要么选择第二个50,要么后续的50一个都不选。当然这时候一个50都不选的情况也是没有正确解的,继续看第三层。

进入第三层dfs还是会有2种选择,要么选择第三个50,要么后续的50一个都不选。但让后续50一个都不选的情况也没有正确解。

…………

依次类推,不难发现,这条while语句的作用就是:营造单一的选1个50,选2个50,选3个50这样的情况,从而避免了重复解的出现。

HDOJ(HDU).1258 Sum It Up (DFS)的更多相关文章

  1. (step4.3.4)hdu 1258(Sum It Up——DFS)

    题目大意:输入t,n,接下来有n个数组成的一个序列.输出总和为t的子序列 解题思路:DFS 代码如下(有详细的注释): #include <iostream> #include <a ...

  2. HDU 1258 Sum It Up(DFS)

    题目链接 Problem Description Given a specified total t and a list of n integers, find all distinct sums ...

  3. HDOJ(HDU).1016 Prime Ring Problem (DFS)

    HDOJ(HDU).1016 Prime Ring Problem (DFS) [从零开始DFS(3)] 从零开始DFS HDOJ.1342 Lotto [从零开始DFS(0)] - DFS思想与框架 ...

  4. HDU 1258 Sum It Up(dfs 巧妙去重)

    传送门: http://acm.hdu.edu.cn/showproblem.php?pid=1258 Sum It Up Time Limit: 2000/1000 MS (Java/Others) ...

  5. hdu 1258 Sum It Up (dfs+路径记录)

    pid=1258">Sum It Up Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (J ...

  6. hdu 1258 Sum It Up(dfs+去重)

    题目大意: 给你一个总和(total)和一列(list)整数,共n个整数,要求用这些整数相加,使相加的结果等于total,找出所有不相同的拼凑方法. 例如,total = 4,n = 6,list = ...

  7. HDU 1258 Sum It Up (DFS)

    Sum It Up Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total S ...

  8. HDU 1258 Sum It Up

    Sum It Up Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total S ...

  9. 【HDOJ】1258 Sum It Up

    典型的深搜,剪枝的时候需要跳过曾经搜索过的相同的数目,既满足nums[i]=nums[i-1]&&visit[i-1]==0,visit[i-1]==0可以说明该点已经测试过. #in ...

随机推荐

  1. 你需要掌握的http知识

    作为一名前端er,http是我们必须要掌握的,那么我们到底需要掌握哪些东西呢 一.基础知识 这里我们介绍与http相关的TCP.IP.DNS.url.uri 1.IP IP地址是我们很熟悉的东西,最常 ...

  2. 快速写一个babel插件

    es6/7/8的出现,给我们带来了很多方便,但是浏览器并不怎么支持,目前chrome应该是支持率最高的,所以为了兼容我们只能把代码转成es5,这应该算是我们最初使用babel的一个缘由,随着业务的开发 ...

  3. Object里面的方法

    object里面有12个方法,没写完,写一些部分代表 toString():输出对象的地址字符串(hashcode码) equals():用的是==,比较的是引用,在有些类里面是重写了这个方法的,重写 ...

  4. Windows运行机理——API与SDK

    Windows运行机理这系列文章都是来至于<零基础学Qt4编程>——吴迪,个人觉得写得很好,所以搬运加以整理. 首先 API:Application Programmaing Interf ...

  5. Django模型与创建管理员用户

    默认情况下, 配置使用SQLite:

  6. Linux命令应用大词典-第19章 文件系统管理

    19.1 mkfs:创建Linux文件系统 19.2 mke2fs:创建ext2.3.4文件系统 19.3 mkfs.ext4:创建ext4文件系统 19.4 mkfs.ext3:创建ext3文件系统 ...

  7. JS变量定义时连续赋值的坑!

    在定义变量时,可以将值相同的变量采用连续赋值的方式,如下代码: var a = b = c = ''; 其实这里面有一个很大很大的坑,以代码说明问题: <script language=&quo ...

  8. LeetCode 100——相同的树

    1. 题目 2. 解答 针对两棵树的根节点,有下列四种情况: p 和 q 都为空,两棵树相同: p 不为空 q 为空,两棵树不相同: p 为空 q 不为空,两棵树不相同: p 和 q 都不为空,如果两 ...

  9. 使用truffle测试部署合约

    truffle console let contract; contract=BloggerCoin.deployed().then(instance=>contract=instanc e);

  10. ServiceStack.Ormlit 使用Insert的时候自增列不会被赋值

    Insert签名是这样的,将第2个参数设置为true就会返回刚插入的自增列ID了,然后可以手工赋值到对象上面去 public static long Insert<T>(this IDbC ...