文章目录
#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])
总结
- dfs先看成遍历二叉树,先写公式部分(要,还是不要),再写终止条件(两个if)。
- 注意递归中的return是返回上一级后继续执行上一级未执行的代码,直到return到传过来的的条件,再返回到main函数中。