问题描述
已知(w1, w2, …, wn)和M,均为正数。要求找出wi的和数等于M的所有子集。

例如:若n=4,(w1,w2,w3,w4)=(11,13,24,7),M=31,则满足要求的子集是(11,13,7)和(24,7).

分析

子集和数问题解的一种表示方法

  • 解由n-元组(x1, x2, …, xn)表示;
  • 显式约束条件xi∈{0,1},1≤i≤n,如果没有选择Wi,则xi=0;如果选择了Wi,则xi=1。于是上面的解可以表示为(1,1,0,1)和(0,0,1,1);
  • 隐式约束条件(xi× wi)的和数为M
  • 解空间的大小为2n个元组
#include<stdio.h>
// 宏定义最大个数MAX
#define MAX 10000
// 设置集合个数
int data[MAX] ;
// 是否选择该元素(True或False)对应与data集合的映射v
bool v[MAX] ;
// 集合元素的个数n,用户输入的子集和目标值c
int n , c ;// 回溯函数traceback
bool traceback(int n)
{// p可以看成是一个指针pointer,或者更准确来说应该是一个游标
// 作为我们[1]数组data和[2]data数组映射子集选中数组v的[游标]
// sum是当前正在跑着的子集的和的值// 对p和sum进行初始化
// 注:p是游标,在C语言中,数组元素下标默认从0开始
int p = 0 ,sum = 0 ;// 判断当前游标的位置
// 游标位置p<0则退出循环
while(p>=0)
{/* 选择新进来的元素 */
// 当v[p]==0进入循环
if(!v[p])
{// 子集中选中v[p]
v[p] = true ;
// 计算子集和,在sum上进行累加data[p]
sum += data[p] ;// 判断当前累加的子集和sum和目标子集和c
// 如果相等
if(c == sum)
// 返回true
// 找到子集和的解
return true ;// 如果当前累加的子集和sum > 目标值c
else if( c < sum)
{// 不选择当前的a[p]值(重置v[p]为False)
// 并在当前子集和sum的基础上减去加上的a[p]
v[p] = false ;
sum -=data[p] ;
}
// 移动游标到下一位
p++ ;
}/* 回溯过程(到最后一个元素都未找到解进入) */
// 检查游标位置p是否跑完数组data集合所有n个元素
// 如果当前游标值p大于等于集合数组data的元素个数n则进入回溯过程
if(p>=n)
{// 到最后一个元素还没加到c,sum<c
// 最后一个元素为True
// 回溯到上次为False的地方在重新开始
while( v[p-1] )
{// p游标自减
p-- ;
// 对当前v[p]赋值
v[p] = false ;
// 跑完整个data数组的n个元素
if(p<1) return false ;
}
//0 1 0 1 0 0 0 1// 到最后一个元素sum>c
// 最后一个元素为False
// 回溯到上次为Ture的地方在重新开始
while( !v[p-1])
{p-- ;
if(p<1) return false ;
}// 回溯过程当前子集和sum也回溯到上次
sum -= data[p-1] ;
// 同时对当前回溯的v[p]重置为false(相当于不要这个元素)
v[p-1] = false ;
}
}// 找不到满足子集和目标值的子集和解
// 退出回溯函数
return false ;
}// 主函数
int main()
{// 读入集合元素个数n,子集和目标值c
scanf("%d %d" , &n , &c) ;
// 依次读入集合中的n个元素
for(int i = 0 ; i < n ; i++)
scanf("%d" , &data[i]) ;// 用回溯法计算子集和
// 判断是否存在结果(存在即traceback的值为True)
// 输出结果
if(traceback(n))
{// traceback函数返回值为true
// 则得到目标值子集和的解
// 输出函数结果int first = 1 ;
// i遍历v,范围是[0, n),即整个集合data数组以及数组v
for(int i = 0 ; i < n; i++)
// 判断v中第(i+1)个元素(v[i])的值是否为0(是否被选中为子集中的元素)
if(v[i])
{// v[i]被选中了作为子集和中的元素// first的值为非0
if(first)
// first变量重置为0
first = 1;
// first的值为0
else
printf(" ") ;
printf("%d " , data[i]) ;
}
printf("\n") ;
}
// traceback函数返回值为False
// 无法得到该目标值子集和的解
else
printf("No Solution!\n") ;return 0 ;
}

引申

一、子集树

**子集树:**当所给的问题是从n个元素的集合S中找出满足某种性质的子集时,相应的解空间称为子集树。

例如,那个物品的0-1背包问题所相应的解空间树就是一颗子集树。这类子集问题通常有2^n
个叶节点,其节点总个数为2(n+1)-1。遍历子集树的任何算法均需要O(2n)的计算时间。

void backtrack (int t)
{
if (t>n) output(x);
else
for (int i=0;i<=1;i++) {
x[t]=i;
if (legal(t)) backtrack(t+1);
}
}

二、排列树
排列树:当所给问题是确定n个元素满足某种性质的排列时,相应的解空间树称为排列树。

排列树通常有n!个叶子节点。因此遍历排列树需要O(n!)的计算时间。

void backtrack (int t)
{
if (t>n) output(x);
else
for (int i=t;i<=n;i++) {
swap(x[t], x[i]);
if (legal(t)) backtrack(t+1);
swap(x[t], x[i]);
}
}

子集和数问题——回溯法(C++)相关推荐

  1. java子集和数问题回溯法算法_子集和数问题_回溯

    有人说算法导论中没有回溯和分支定界这两种算法.我觉得这个算是导论中算法的应用吧,废话不多说,走起. 回溯算法之子集和数问题. 这个算法要解决的问题:假定有N个不同的正数(通常称为权),要求找出这些数中 ...

  2. 算法分析-子集和数,回溯法

    #include <iostream> #include <algorithm>/*题目描述 子集和问题的一个实例为〈S,t〉.其中,S={ 1 x , 2 x ,-, n x ...

  3. 0x08算法设计与分析复习(二):算法设计策略-回溯法2

    参考书籍:算法设计与分析--C++语言描述(第二版) 算法设计策略-回溯法 子集和数 问题描述 已知n个不同的正数wi(0≤i≤n−1)的集合,求该集合的所有满足条件的子集,使得每个子集中的正数之和等 ...

  4. 回溯法(算法分析与设计)

    0.回溯法的算法框架 A.简介 回溯法,又称试探法.一般需要遍历解空间,时间复杂度概况:子集树Ω(2^n),排序树Ω(n!),暴力法 B.回溯法解题三步骤 1)定义问题的解空间 如0-1背包问题,当n ...

  5. [回溯算法] 五大常用算法之回溯法

    算法入门6:回溯法 一. 回溯法 – 深度优先搜素 1. 简单概述 回溯法思路的简单描述是:把问题的解空间转化成了图或者树的结构表示,然后使用深度优先搜索策略进行遍历,遍历的过程中记录和寻找所有可行解 ...

  6. 五大常用算法之回溯法详解及经典例题

    一. 回溯法 – 深度优先搜素 1. 简单概述 回溯法思路的简单描述是:把问题的解空间转化成了图或者树的结构表示,然后使用深度优先搜索策略进行遍历,遍历的过程中记录和寻找所有可行解或者最优解. 基本思 ...

  7. python 回溯法 子集树模板 系列 —— 3、0-1背包问题

    问题 给定N个物品和一个背包.物品i的重量是Wi,其价值位Vi ,背包的容量为C.问应该如何选择装入背包的物品,使得放入背包的物品的总价值为最大? 分析 显然,放入背包的物品,是N个物品的所有子集的其 ...

  8. 回溯法——打印子集树

    打印子集树.比如说有三个元素,用0和1表示子集有或者没有这个元素,向左分支走为1,向右分支走为0,那么如下图所有路径都可以用0和1表示出来,可以用0和1完整表示子集.0就不打印对应的元素,1就打印对应 ...

  9. python找零钱问题_Python基于回溯法子集树模板解决找零问题示例

    本文实例讲述了Python基于回溯法子集树模板解决找零问题.分享给大家供大家参考,具体如下: 问题 有面额10元.5元.2元.1元的硬币,数量分别为3个.5个.7个.12个.现在需要给顾客找零16元, ...

最新文章

  1. 归并排序 java实现_归并排序的java实现
  2. 矛与盾:二进制漏洞攻防思想对抗
  3. 工具 左侧服务列表_协作办公时代,在线编辑文档工具,安排!
  4. Faster RCNN 训练自己的检测模型
  5. WMI使用的WIN32_类库名
  6. 剑指Offer - 面试题66. 构建乘积数组(正反遍历)
  7. 动态生成的html元素无法调用js函数,在调用js函数之前,如何确保将动态生成的div加载到DOM中?...
  8. 如何为活动设计海报|优秀案例,分享关键技巧
  9. IOS UIColor 自定义颜色
  10. Android APK反编译详解 .
  11. 《人工智能 一种现代方法》第三版 第1章 概述 笔记摘录
  12. 买电梯房几楼才是最好 几个最差楼层千万不能选
  13. 《C陷阱与缺陷》 阅读总结
  14. PCB LAYOUT特殊走线总结
  15. 大一上:计算机导论复习(每章分值、常考题型以及部分章节课后习题答案【网上没有,老师自己做的】)
  16. Bitbucket相关
  17. 电源完整性之DC-DC
  18. 《金字塔原理》读书思维导图
  19. CCS/TMS320F28377D: EMIF interface - CS2-CS4 start address configuration CS2-CS4起始地址
  20. pap认证失败_PPP(CHAP 或 PAP)认证故障排除

热门文章

  1. 分布式面试 - 分布式锁的常见问题
  2. Use Visual Studio Code to create and run Transact-SQL scripts for SQL Server
  3. oracle一个lun多大,Oracle RAC中验证LUN_ID对应情况
  4. Linux系统学习 八、SSH服务—SSH远程管理服务
  5. leetcode 最长回文子串
  6. linux运行级别与服务
  7. 山东大学有人陪!真的吗?_10,000小时! 您真的需要那么多吗?
  8. 微信支付开放平台_有了开放数据,您终于可以得到这些年来所支付的费用
  9. python lxml模块解析html_用lxml解析HTML
  10. Stateflow中的真值表注意事项