P2404 数的拆分中看递归算法

Hello!我是C风,专注与算法以及Java的学习,今天我们就来看一下数的拆分这个题目,并由此来总结一下递归算法。
话不多说,我们先来看一下这道题目:
题目描述:

任何一个大于1的自然数n,总可以拆分成若干个小于n的自然数之和。现在给你一个自然数n,要求你求出n的拆分成一些数字的和。每个拆分后的序列中的数字从小到大排序。然后你需要输出这些序列,其中字典序小的序列需要优先输出。

输入格式:

输入:待拆分的自然数n。

输出格式:

输出:若干数的加法式子。

输入:

7

输出:

1+1+1+1+1+1+1
1+1+1+1+1+2
1+1+1+1+3
1+1+1+2+2
1+1+1+4
1+1+2+3
1+1+5
1+2+2+2
1+2+4
1+3+3
1+6
2+2+3
2+5
3+4

这个题目就是将一个数不断拆分的过程,这里我们观察发现输出的首项是小于输入数字的一半的,我们首先就要想一下这个过程是如何的。
这其实就是一个DFS题目,首先就是将7拆分成1,2,3;之后再将拆分之后的数继续拆分直到最后只剩0;所以只要这样一想,我们就直到这是一道的典型的DFS题,按照我上一篇博客讲的,这里的递归结束条件就是不能继续拆分,另外一个需要注意的点拆分层的下一层的数要比该层大或者相等,也就是说第一步拆分2后就不能再拆1了
所以这样一想我们的关键函数就可以写出来了,不一定要if语句来表示递归结束的条件,这里我们输入数据后在循环条件里面就会自己进入下一个分支,当num == 1时循环就会结束,也就是没有其他的分支时那就会结束,所以我们就不要过于死板,这里就在for循环的下面加上递归结束的配套代码即可。这里主要时一开始没有思考,不知道start的作用。这个start的作用就是让子支大于等于主支,并且在循环过程中会自动更新num的值。

int DFS(int num,int loadnum, int start)
{//loadnum记录我们输入的数,因为再递归时num会变化
		for (int i = start; i <= num / 2; i++)//这里就是找不到分支的时候结束循环
		{//所以就不需要另加结束条件,但是要删除一个num = 4
			Load[t] = i;
			t++;
			DFS(num - i,loadnum, i);
			t--;
		}
		if (num == loadnum)
		{
			return 0;//这样也结束
		}
		cnt++;
		Load[t] = num;
		print(Load);
		return 0;// 递归结束条件就是不满足上述关系
}

接下来就是我们的打印函数了,这里就只需要注意一下打印的格式就好了

void print(int* Load)
{
	for (int i = 0; i < t; i++)
	{
		printf("%d+", Load[i]);
	}
	printf("%d\n", Load[t]);
}

之后的主函数当然就不需要解释了,但是为了代码的完整性,我还是也上传一下

int cnt = 0;
int Load[10];
int t = 0;
············
int main()
{
	int num;
	int loadnum;
	cin >> num;
	loadnum = num;
	DFS(num,loadnum, 1);
	//printf("%d", cnt);//这个可以记录一共有多少种拆法
}

这里我定义了几个全局变量,其实是可以变成非全局变量的,这里以减少全局变量t为例,我们可以在主函数里定义一个t,然后在DFS函数与print函数里都加一个变量,这样其范围就减少很多了,但是我们需要注意这是值传递,t的值本身没有变化。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值