[递归例题总结]--正整数n,按第一项递减的顺序依次输出其和等于n的所有不增的正整数和

[递归例题总结]–正整数n,按第一项递减的顺序依次输出其和等于n的所有不增的正整数和

题目内容

题目编号:Exp08-Basic01,GJBook3-12-05
题目名称:正整数分解
题目描述:正整数n,按第一项递减的顺序依次输出其和等于n的所有不增的正整数和式。

输入:一个正整数n(0<n≤15)。
输出:每行输出如样例所示,和等于n的不增正整数和式,数字和运算符间无符号,最后一行结尾有一个回车换行符。
样例:
输入:
4
输出:
4=3+1
4=2+2
4=2+1+1
4=1+1+1+1

#include <stdio.h >
int num;
void print(int a[],int n)
{
	int i;
	printf("%d=%d",num,a[0]);
	for(i=1;i<=n;i++) printf("+%d",a[i]);
	printf("\n");
	return ;
}/*输出函数*/
int check(int a[],int n)
{
	int i;
	for(i=0;i<n;i++)
	{
		if(a[i]<a[i+1]) return 0;
	}
	return 1;
}/*判断是否为降序*/

void lines(int n,int a[],int tot)
{
	
	int i,j,k;
	for(i=n-1;i>0;i--)
	{
		j=n-i;
		a[tot]=i;a[tot+1]=j;/*将拆分的数存储到输出数组中*/
		if(check(a,tot+1)) print(a,tot+1);
		if(j>1){
			lines(j,a,tot+1);
		}	
	}
}

int main()
{
	scanf("%d",&num);
	int a[num];
	lines(num,a,0);
	return 0;
 } 

相似例题

题目描述:从前n个自然数1,2,3……n中取r个数做组合,打印所有的组合。
输入:两个正整数,分别为n和r的值。
输出:见样例
样例:
输入:5 3
输出:
1 2 3
1 2 4
1 2 5
1 3 4
1 3 5
1 4 5
2 3 4
2 3 5
2 4 5
3 4 5

#include <stdio.h>
int m,n;
void print(int a[],int up)
{
	int i;
	for(i=0;i<up;i++)
	printf("%d  ",a[i]);
	printf("\n");
	return ;
}/*输出函数*/ 
void lines(int a[],int num,int tot) 
{
	if(tot==n)
	{
		print(a,tot);
		return; 
	}/*递归终止与输出判断*/
	int i;
 	for(i=num;i<=m;i++)
	{
		a[tot]=i;
		lines(a,i+1,tot+1);
		}	
}/*递归并向输出数组中赋值*/
int main()
{
	scanf("%d%d",&m,&n);
	int a[n];/*存储数字组合*/
	lines(a,1,0);
	return 0;
}

总结

1.两题输格式决定两段代码只能采用递归进行解决,同时程序的输出是在函数递归到最后统一输出之前递归的所有结果,针对此种特点递归做出以下两点适应

a)定义一个数组储存所每一层递归的结果,以实现在递归结束时统一输出所有结果,并不影响递归的继续执行
b)在递归到返回条件时先调用一个输出函数输出结果,在return到上一层递归。

2.两个程序均在递归内使用了for循环语句,通过for语句实现了给定范围内某种数字组合规则下所有情况的枚举。实现了未知大小的树状数据结构的扫描。

3.最后,笔者在打这两段代码时充分体会到递归程序的特点即为不断重复某种操作,且重复次数往往不可知,最终结果是每次重复操作的积累或集合。针对此种特点编写的思路就是:

a)先对解决问题所需的语句与数据结构有大概的规划。
b)先简单编写(不考虑递归的实现)其中某层的执行代码。
c)考虑整体的递归执行,加入递归操作,(有时需)修改形参列表 。
d)加入递归截止条件.

当然一次性成功的可能性是较小的(就笔者而言),所以还需进行调试,修补语法,算法错误。

以第一题为例,具体实操.

一.编写主函数:
#include <stdio.h>
int num;
int main()
{	scanf("%d",&num);
	int a[num];
	lines(num,a,0);
	return 0;  }
二. 本递归要用到for循环以及数组a[]分别实现枚举和存储输出:
void lines(int n,int a[],int tot)
{
	int i,j,k;
	for(i=n-1;i>0;i--)
	{
		j=n-i;
a[tot]=i;a[tot+1]=j;
	}
}
三.实现递归,确定本次函数与下一次递归参数之间的传递关系:
void lines(int n,int a[],int tot)
{
	int i,j,k;
	for(i=n-1;i>0;i--)
	{
		j=n-i;
		a[tot]=i;a[tot+1]=j;
		if(j>1) lines(j);
	}
}
四.实现递归终止,并在返回前输出,且为了适应题中的不增要求加入检查函数:
void print(int a[],int n)
{
	int i;
	printf("%d=%d",num,a[0]);
	for(i=1;i<=n;i++) printf("+%d",a[i]);
	printf("\n");
	return ;
}
int check(int a[],int n)
{
	int i;
	for(i=0;i<n;i++)
	{
		if(a[i]<a[i+1]) return 0;
	}
	return 1;
}

void lines(int n,int a[],int tot)
{
	
	int i,j,k;
	for(i=n-1;i>0;i--)
	{
		j=n-i;
		a[tot]=i;a[tot+1]=j;
		if(check(a,tot+1)) print(a,tot+1);
		if(j>1){
			lines(j,a,tot+1);
		}	
	}
}
                                                    代码新手,欢迎斧正!!
  • 11
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值