7-1 凑零钱 (30分)(dfs和递归的理解

原题目

#include<iostream>
#include<algorithm>
using namespace std;
int arr[10000];
int sum[10000];
int take[10000];
int n, m;
bool flag = 0;
void dfs(int x,int num,int h)
{
	if (flag||h + sum[x] < m)//x==n不在这里的原因是3 5,2 2 1的情况会是no solution
		return;
	if ( h >=m||x == n)
	{
		if (h == m)
		{
			flag = 1;
			cout << take[0];
			for (int i = 1; i < num; i++)
				cout << " " << take[i];
			cout << endl;
		}
		return;
	}
	take[num] = arr[x];
	dfs(x + 1, num + 1, h + arr[x]);//取了当前的硬币,这时的h变为h+arr[x】,传参时arr[x]的x和take[num]的num均加1
	dfs(x + 1, num, h);
}
int main()
{
	cin >> n >> m;
	int i, j;
	for (i = 0; i < n; i++)
		cin >> arr[i];
	sort(arr, arr + n);
	sum[n - 1] = arr[n - 1];
	for (i = n - 2; i >= 0; i--)
		sum[i] = arr[i] + sum[i + 1];
	dfs(0, 0, 0);//遍历树的起点
	if (!flag)
		cout << "No Solution" << endl;
	return 0;
}

知识点1,剪枝

dfs可看为二叉树的深度遍历,dfs(0,0,0)是遍历的起点,当遍历全部情况后,又返回到起点之后最后返回到mian()函数中。

if (flag||h + sum[x] < m)//x==n不在这里的原因是3 5,2 2 1的情况会是no solution
		return;
	if ( h >=m||x == n)
	{
		if (h == m)
		{
			flag = 1;
			cout << take[0];
			for (int i = 1; i < num; i++)
				cout << " " << take[i];
			cout << endl;
		}
		return;
	}

其中这两个if()语句是为了剪枝操作,放flag变为1后,就没有必要进行接下来的遍历了,所以直接返回上一层递归。同理当h+剩余的所有数还<m,则也不需要递归,直接返回上一层递归,直到返回到起点(0,0,0)返回main函数。

递归中的return语句,都是返回到递归的上一层当中,比如调用递归的是A,经过一些列过程最后返回到A,接下来才能返回到main函数中。

以猴子吃桃来理解递归的return

#include <stdio.h>
#include<iostream>
using namespace std;
int getPeachNumber(int n)
{
	int num;
	if (n == 3)
	{
		/*num = 1;
		printf("第%d天所剩桃子%d个\n", n, num);		
		return num;	*/
		return 1;
	}
	else
	{
		num = (getPeachNumber(n + 1) + 1) * 2;

		printf("第%d天所剩桃子%d个\n", n, num);

	}
	return num;
}

int main() {
	int num = getPeachNumber(1);
	printf("猴子第一天摘了:%d个桃子。\n", num);
	return 0;
}
  • 运行结果为
  • 调试的过程为1,2,3,再3-2-1,返回到main函数。回溯的过程为,n=2时,返回getpeachnumber(n+1)的值为1,则第二天的计算出值为(1+1)*2=4;最后得出n=1的时候,函数返回为10.
    若代码写成这样
if (n == 3)
	{
		/*num = 1;
		printf("第%d天所剩桃子%d个\n", n, num);		
		return num;	*/
		printf("第%d天所剩桃子%d个\n", n, num);
		return 1;
	}

则会报错
在这里插入图片描述错误同int n;cout<<n;一样。

return用来中断返回值为void类型的函数的执行。return 0;则是return的另一种用法,专用于返回值非void的函数返回其值。参考博客

凑零钱中的递归过程


3 5
1 2 3为例子

ps:调试的时候可以用f11,添加并行监视来查看。
(二叉树,左孩子为要arr[x])
在这里插入图片描述
在这里插入图片描述

总结

  1. dfs先看成遍历二叉树,先写公式部分(要,还是不要),再写终止条件(两个if)。
  2. 注意递归中的return是返回上一级后继续执行上一级未执行的代码,直到return到传过来的的条件,再返回到main函数中。
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值