SWUST OJ#963(小偷的背包问题与递归讲解)

目录

递归前言

构成递归需具备的条件

题目

输入

输出

思路

代码

代码过程演示


递归前言

粽所粥汁,计算n的阶乘,斐波那契数列,汉诺塔问题,和二叉树,背包问题等,都可谓是递归的应用,经典之经典!那什么(๑•̌.•̑๑)ˀ̣ˀ̣是递归呢? 

看,这就叫递“龟”,这篇博客写完了,哈哈!

好了(ง •̀_•́)ง,不开玩笑了,说正经的,为了让大家更好的理解,博主给大家讲一个故事吧!希望大家认真听~
  听懂了故事就弄懂了递归,从前有个小破站,站里有个新博主,新博主主动给大家讲故事,讲了什么故事呢?讲了从前有个小破站,站里有个新博主,新博主主动给大家讲故事,讲了什么故事呢?讲了从前~

大家看,这个故事有什么特点,他的特点是,在故事中再次提到相同的故事,这就是递归的核心理念了,回到编程领域,我们知道,一个函数是可以调用另一个函数的,作为特例,如果一个函数调用了自己,就像故事中提到了同样的故事

 我们把函数在运行时,调用自己的情况,叫做递归!  也可以称之为有限“套娃”!


构成递归需具备的条件

1. 子问题须与原始问题为同样的事,且更为简单;
2. 不能无限制地调用本身,须有个出口,化简为非递归状况处理。

注:其实递归是从递归入口一层一层,往下递归,直到遇到递归出口才一层一层的反弹,最终会反弹到调用处!现在用阶乘为例,带大家了解一下过程!

int f(int n)
{
	if (n == 1)
		return 1; //递归终止条件
	else
		return n * f(n - 1); //调用自己
}

这个递归在熟悉不过了,第2-3行是终止条件,第5行是调用自己。接下来我们就用n等于5的时候来画个图看一下递归究竟是怎么调用的 !

现在大家应该对递归有了一个初步的理解吧!(博主也是这几天在恶补,时间也很紧,就先写这么多吧)!接下来就开始题目解析咯!


题目

题目描述

设有一个背包可以放入的物品重量为S,现有n件物品,重量分别是w1,w2,w3,…,wn。问能否从这n件物品中选择若干件放入背包中,使得放入的重量之和正好为S。如果有满足条件的选择,则此背包有解,否则此背包问题无解。

输入

第一行为物品重量S(整数);
第二行为物品数量n,
第三行为n件物品的重量的序列。

输出

有解就输出”yes!“,没有解就输出”no!“。

样例输入

20

5

1 3 5 7 9
 

样例输出

yes!

思路

我认为一个物品,只有会出现两种状态,一个就是放入背包,一个就是不放入,而递归的终止条件,也有两种状态,第一是背包剩余容量为0,第二就是背包剩余容量为负数,或者是物品放完了刚好。接下来博主会通过代码详细讲解,带大家进一步理解,这段话。

代码

#include <algorithm>
#include <iostream>
using namespace std;
int wi[10005];
int bag(int s, int n)//遍历所有组合
{
	if (s == 0)
		return 1;
	else if (s < 0 || n == 0)
		return 0;
	else if (bag(s - wi[n], n - 1))//将a[n]放进背包
		return 1;
	else
		return bag(s, n - 1);//不将a[n]放进背包
}
int main()
{
	int n, i, s;
	cin >> s >> n;
	for (i = 1; i <= n; i++)
		cin >> wi[i];
	if (bag(s, n))
		cout << "yes!";
	else
		cout << "no!";
	return 0;
}

代码过程演示

20
5
1 3 5 7 9
a[1]=1;a[2]=3;a[3]=5;a[4]=7;a[5]=9;
首先是主函数中if(bag(20,5))
(1)bag(20,5)
if (s == 0) return 1;//不成立,执行下一条语句
if (s < 0 || n == 0) return 0;//不成立,执行下一条语句
if (bag(s - wi[n], n - 1)) return 1;//这一条语句的执行情况,要看bag(11,4)的情况

(2)bag(11,4)
if (s == 0) return 1;//不成立,执行下一条语句
if (s < 0 || n == 0) return 0;//不成立,执行下一条语句
if (bag(s - wi[n], n - 1)) return 1;//这一条语句的执行情况,要看bag(4,3)的情况

(3)bag(4,3)
if (s == 0) return 1;//不成立,执行下一条语句
if (s < 0 || n == 0) return 0;//不成立,执行下一条语句
if (bag(s - wi[n], n - 1)) return 1;//这一条语句的执行情况,要看bag(-1,2)的情况

(4)bag(-1,2)
if (s == 0) return 1;//不成立,执行下一条语句
if (s < 0 || n == 0) return 0;//成立,返回bag(-1,2)=0;

//这时返回去看bag(4,3)的情况
(3)bag(4,3)
if (s == 0) return 1;//不成立,执行下一条语句
if (s < 0 || n == 0) return 0;//不成立,执行下一条语句
if (bag(s - wi[n], n - 1)) return 1;//因为bag(-1,2)=0,所以不成立,执行就下一条语句
return bag(s, n - 1);//现在此时bag(4,3)的取值 则取决于bag(4,2);

(5)bag(4,2)
if (s == 0) return 1;//不成立,执行下一条语句
if (s < 0 || n == 0) return 0;//不成立,执行下一条语句
if (bag(s - wi[n], n - 1)) return 1;//这一条语句的执行情况,要看bag(1,1)的情况

(6)bag(1,1)
if (s == 0) return 1;//不成立,执行下一条语句
if (s < 0 || n == 0) return 0;//不成立,执行下一条语句
if (bag(s - wi[n], n - 1)) return 1;//这一条语句的执行情况,要看bag(0,0)的情况

(7)bag(0,0)
if (s == 0) return 1;//成立,此时bag(0,0)=1

(6)bag(1,1)
if (s == 0) return 1;//不成立,执行下一条语句
if (s < 0 || n == 0) return 0;//不成立,执行下一条语句
if (bag(s - wi[n], n - 1)) return 1;//成立,此时bag(1,1)=1;

(5)bag(4,2)
if (s == 0) return 1;//不成立,执行下一条语句
if (s < 0 || n == 0) return 0;//不成立,执行下一条语句
if (bag(s - wi[n], n - 1)) return 1;//成立,此时bag(4,2)=1;

(4)bag(4,3)
if (s == 0) return 1;//不成立,执行下一条语句
if (s < 0 || n == 0) return 0;//不成立,执行下一条语句
if (bag(s - wi[n], n - 1)) return 1;//bag(-1,2)=0,不成立
return bag(4,2)//bag(4,3)=bag(4,2)=1

(3)bag(11,4)
if (s == 0) return 1;//不成立,执行下一条语句
if (s < 0 || n == 0) return 0;//不成立,执行下一条语句
if (bag(s - wi[n], n - 1)) return 1;//成立,此时bag(11,4)=1

(2)bag(20,5)
if (s == 0) return 1;//不成立,执行下一条语句
if (s < 0 || n == 0) return 0;//不成立,执行下一条语句
if (bag(s - wi[n], n - 1)) return 1;//成立,此时bag(20,5)=1

(1)if(bag(20,5))//成立,输出"yes!"


终于写完了,自己也清楚多了!加油!加油!加油!打败敌人吹气球~
 看完了,别忘了,给博主点个关注哦!

  • 22
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 17
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

詹小友

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值