递归思想即背包问题

01背包问题:

1.递归思想

0- 1 背包问题如果采用递归算法来描述则非常清楚明白, 它的算法根本思想是假设用布尔函数
knap( s, n) 表示n 件物品放入可容质量为s 的背包中是否有解( 当knap 函数的值为真时

说明问题有解,其值为假时无解) . 我们可以通过输入s 和n 的值, 根据它们的值可分为以下几种情况讨论:

( 1) 当s= 0时可知问题有解, 即函数knap( s, n) 的值为true; ( 2) 当s< 0 时这时不可能,

所以函数值为false; ( 3) 当输入的s> 0 且n< 1 时即总物品的件数不足1, 这时函数值为false,

只有s> 0 且n \1 时才符合实际情况,这时又分为两种情况: ( 1) 选择的一组物体中不包括Wn

则knap( s, n) 的解就是knap( s, n- 1) 的解. ( 2) 选择的一组物体中包括Wn 则knap( s, n) 的解

就是knap( s- Wn, n- 1) 的解. 这样一组Wn 的值就是问题的最佳解. 这样就将规模为n 的问题转化为

规模为n- 1 的问题. 综上所述0- 1 背包问题的递归函数定义为:
knap( s, n) =∕true, s= 0
             ︳false, s< 0
             ︳false, s> 0 且n< 1
              \knap( s, n- 1) 或knap( s- Wn, n- 1) , s> 0 且n>= 1
采用此法求解0- 1 背包问题的时间复杂度为O( n) . 上述算法对于所有物品中的某几件恰能装满背包
时能准确求出最佳解. 但一般情况是对于某一些物品无论怎么装都不能装满背包, 必须要按背包的最大
容量来装. 如物品件数为4, 其质量分别为: 10, 2, 5, 4, 背包的容量为20, 则这四件物品无论怎么放都不
能恰好装满背包, 但应能最大限度装, 即必须装下10, 5, 4 这三件物品, 这样就能得到最大质量19. 对于
这种装不满的背包它的解决办法是这样的: 按所有物品的组合质量最大的方法装背包, 如果还装不满,
则我们可以考虑剩余空间能否装下所有物品中最小的那件, 如果连最小的都装不下了则说明这样得到
的解是最佳解, 问题解决. 这样我们必须先找出所有n 件物品中质量最小的那件( 它的质量为Min) , 但
是为了问题的解决我们不能增加运算次数太多, 并且必须运用上述递归函数. 那么我们可通过修改s 的
值即背包的容量, 从背包容量s 中减去k( 它的值是从0 到Min- 1 之间的一个整数值) , 再调用递归函
数. 当k= 0 时即能装满背包, 其它值也能保证背包能最大限度装满, 这样所有问题都解决了.
Description
设有一个背包可以放入的物品重量为S,现有n件物品,重量分别是w1,w2,w3,…wn。
问能否从这n件物品中选择若干件放入背包中,使得放入的重量之和正好为S。
如果有满足条件的选择,则此背包有解,否则此背包问题无解。

Input输入数据有多行,包括放入的物品重量为s,物品的件数n,以及每件物品的重量(输入数据均为正整数)
多组测试数据。
Output对于每个测试实例,若满足条件则输出“YES”,若不满足则输出“NO“
Sample Input
20 5
1 3 5 7 9
Sample Output
YES

复制代码
# include<stdio.h>
# include<string.h>
int date[1005];
int f(int w,int s)
{
    if(w==0) return 1;//正好
    if(w<0||w>0 &&s==0) return 0;
    if(f(w-date[s],s-1)) return 1;//退出来再选下一个
    return f(w,s-1);//选择下一个
}

int main()
{
 int i,Weight,n;
 while(scanf("%d %d",&Weight,&n)!=EOF)
 {
     memset(date,0,sizeof(date));
 for(i=1;i<=n;i++)
  scanf("%d",&date[i]);
    if(f(Weight,n))
       printf("YES\n");
 else printf("NO\n");
 }
 return 0;
}
}
http://i.cnblogs.com/EditPosts.aspx?opt=1
时间: 2024-10-18 13:55:33

递归思想即背包问题的相关文章

算法之递归思想

树的遍历的实现就是典型的递归思想. /* * description:树的遍历示例,递归 * 访问顺序: * 前序: 当前节点 - 左子树 - 右子树 * 中序: 左子树 - 当前节点 - 右子树 * 后序: 左子树 - 右子树 - 当前节点 * * writeby: nick * date: 2012-10-22 23:56 */ #include <iostream> using namespace std; struct node { int item; node *l, *r; nod

关于回调和递归思想的理解

1) 面向过程的递归思想在面向对象的编程世界中的递归调用就是回调思想.它们两个的区别就是多了一个封装了方法和属性的对象.回调函数实参传递的是一个函数的指针,其实递归调用也是用函数的相同地址进行递归循环处理数据的.递归函数的原理就是函数的参数值不断地变化,从而不断的重新回到函数的起始地址处根据传递的参数值不断地处理数据.回调函数的原理就是把函数当做一个可以传递的实参赋值给自定义的回调函数的形参,实际传递的是定义函数的地址. a) 理解回调函数最好把函数和类型对象相当,因为他们都是数据变量的集合,都

第二篇 递归思想

今天说说递归思想,在我们编码时,有的时候递归能够让我们的算法更加通俗易懂,并且代码量也是大大的减少.比如我先前的系列中说到了 关于树的“先序,中序和后序”遍历,那么看看用递归来描叙这个问题是多少的简洁,多么的轻松. 1 #region 二叉树的先序遍历 2 /// <summary> 3 /// 二叉树的先序遍历 4 /// </summary> 5 /// <typeparam name="T"></typeparam> 6 /// &

----斐波那契数列---eval函数----类递归思想 栈 进出 思想

------------ 斐波那契 数列 --------------- [1,1,2,3,5,8,13,21,34,...] 1 列表方法实现 # l=[1,1] # # # while len(l)<=20: # # l.append(l[-1]+l[-2]) # # print(l) # # while len(l)!=4: # l.append(l[-1]+l[-2]) # print(l) # 2 迭代实现 # n=10 # # n1 = 1 # n2 = 1 # n3 = 1 # #

由递归思想处理问题的基本原则

我的主力博客:半亩方塘 在我的博文关于递归的一些简单想法,我用自己的理解谈了一些关于递归的看法,下面用 <数据结构与算法分析--C语言描述> 一书中第 9 页的四条基本原则将我的思想加以规范化,并在后续的不断加强学习中不断完善本文的内容. 在编写递归程序的时候,要牢记递归的四条基本原则: 基准情形:必须总有某些基准情形,它无需递归就能解出 -- 构成递归终止条件 不断推进:对于那些需要递归求解的情形,每一次递归调用都必须要使求解状况朝接近基准情形的方向推进 -- 由初始情形通过递归调用不断向递

分治策略结合递归思想求最大子序列和

我的主力博客:半亩方塘 对于 <数据结构与算法分析--C语言描述> 一书第 20 页所描述的算法 3,相信会有很多人表示不怎么理解,下面我由具体问题的求解过程出发,谈谈我自己的理解: 首先,什么是分治法呢?所谓 分治法,就是 将一个问题的求解过程分解为两个大小相等的子问题进行求解,如果分解后的子问题本身也可以分解的话,则将这个分解的过程进行下去,直至最后得到的子问题不能再分解为止,最后将子问题的解逐步合并并可能做一些少量的附加工作,得到最后整个问题的解.在求解原来整个问题的算法思想,与求解每一

04-03构造递归思想_串的比较

串的比较 比较两个串的内容是否相同的规则是: 比较对应位置的每个字母,出现一处不同,则不相同. 一个串为空时,另一个不空,则不同. 请用递归的方法,重现实现比较两个串的内容是否相同. public class MyA { static boolean compare(String a, String b) { if(a.length() != b.length()) return false; if(a.length()==0) return true; if(a.charAt(0) != b.

二叉树的非递归遍历(借鉴递归思想实现非递归遍历)

1 // 树结点定义 2 typedef struct TNode 3 { 4 int value; 5 TNode *left; 6 TNode *right; 7 }*PTNode; 1. 前序遍历的非递归实现(借鉴递归思想实现) 思想: 访问到一结点时,先将其入栈,假设入栈节点为P. 访问P,将P的右孩子和左孩子依次入栈,这样就保证了每次左孩子在右孩子前面被访问. 1 void preOrderNoneRecursion(PTNode root) 2 { 3 if(root == NULL

递归思想之---斐波拉契数列

斐波那契数列中的递归思想 ??如果上述的分析都明白了,那就说明你已掌握了递归,但为了加深对递归的理解,我们再来看一个思考题(来自程序员的数学思考题),题目是这样的,假如动物中有一种特殊的种类,它出生2天后就开始以每天1只的速度繁殖后代.假设第1天,有1只这样的动物(该动物刚出生,从第3天开始繁殖后代).那么到第11天,共有多少只呢? 我们先来按一般顺序思考,先不要考虑第11天,先从第1天开始,看能不能找出规律: [第1天]只有1只动物 [第2天]只有1只动物,还没有繁殖后代,总量为1 [第3天]