有序全排列的题型对比,例如硬币问题和整数分解问题

题目一:输入n(1-10之间数字),将数字分解显示,如6可以显示为6,5+1,4+2,4+1+1..... 。

题目二:用递归实现,显示用1分、2分和5分的硬币凑成1元,一共有多少种方法。


      从两个题目的论述中,我们不能发现:题目一是将一个数分解成用1,2,3,4,........,9这样的数列来表示,题目二则是用特定的数列,如1,2,5,来进行分解整数。两者具有相似之处,但也应该看到我们要找到的排列是有序的,比如说:6=4+2;与6=2+4;是属于同一种方法,因此在编写程序的时候要注意这一点的区别。

      因为题目一较为简单,我们先对其进行分析。这里我们假设要分解的数字是n,使用一个栈来记录分解的数字,定义一个全局变量sum记录分解数字的和。那么递归的出口就是:sum == n。当条件满足时,说明我们找到了一种方法,这时便使用循环输出结果即可。

      那么递归体呢?这里不妨采用由大到小的分解方法,假设要被分解的数是6。从大到小的分解的话,那么第一次尝试填进数组的是6,sum求和得到6,则输出这个结果,返回递归的上一层。之后尝试填入5,sum求和不等于6,则递归的进行下一次的填数,那么下一次的填数应该是填几呢?很显然应该尝试填入5(这样就能保证每次新填入的数字<=上一次的数字,使得不会出现2+4 和 4+2 的情况,有序的排列了),5+5>6,所以应减小,填4,填3.....直到填1为止。


这里我们看一下代码:

int stack[10],n;
int  sum=0,top = 0;
void devi(int index ){                           //index初试化为 n
	
	if(sum == n){
		printf("%d=",n);
		
		for(int i =0;in) return ;                    //若大于n,则直接返回
	for(int i = index;i>=1;i--){
		
		sum = sum+i;                //sum为全局变量,起到求和目的
		stack[top++] = i;
		devi(i);                    //递归的进行下一次的填数,传入i,保证了有序性
		sum -=i;                    //由下一层返回到这一层,将填入的数减去,并弹出
		top--;
		                            //i--尝试填入较小的数
	}

}

好,让我们看看全部的代码:

#include

//输入n(1-10之间数字),将数字分解显示,如6可以显示为6,5+1,4+2,4+1+1..... 
int stack[10],n;
int  sum=0,top = 0;
void devi(int index ){
	
	if(sum == n){
		printf("%d=",n);
		
		for(int i =0;in) return ;
	for(int i = index;i>=1;i--){
		
		sum = sum+i;
		stack[top++] = i;
		devi(i);
		sum -=i;
		top--;
		
	}

}

int main(){
	
	while(scanf("%d",&n)!=EOF){
		
		devi(n);
		
	}
	
	return 0;
	
}

来看看运行的结果:


第二道题目:这道题目和上道思路是一样的,不同的是这次选择填入的数不在是1,2,3,.........9,这样连续的值,而是1,3,5。这时我们可以使用一个数组将数字存起来,用循环遍历数组下标就可以用money[i]来填数了。(自然这里的1元转换成100)

看看代码:

#include 

//用递归实现,显示用1分、2分和5分的硬币凑成1元,一共有多少种方法。

int money[3] ={1,2,5};
int stack[101],top=0,n;
int sum =0,count =0;
void fun(int index){         //index  0  1  2 
	
	if(sum == n){
		count++;
		/*  printf("%d=",n);                    //假如你想输出组合,也是可以的
		for(int i =0;in) return ;
	for(int i =index;i>=0;i--){
		
		sum+=money[i];
		stack[top++] = money[i];
		fun(i);
		sum-=money[i];
		top--;
		
	}

}

int main(){
	
	while(scanf("%d",&n)!=EOF){
		
		fun(2);                        //这里一定是2,因为money[2] = 5,从大到小的排列
		
		
		printf("种类为:%d",count);
		
	}

	return 0;
	
} 
运行的结果图:

以上就是两个题目的介绍。对于像走楼梯的这样的问题,是不需要考虑排列的顺序的,即1+2和2+1为两个方法,那么就不需要考虑填数时要小于上次的数字了,这样就没有以上两个题目麻烦一些。自然这样的题目,或许用斐波那契数列的想法更加简洁。

比如:一次能上1,2和3个台阶,问登上n阶台阶,有几种方法??

代码如下:

#include  
int step(int n){
	
	if(n==1) return 1;
	if(n==2) return 2;
	if(n==3) return 4;
	return step(n-1)+step(n-2)+step(n-3);
	
}

int main(){
	
	int n;
	scanf("%d",&n);
	
	printf("%d",step(n));
	
	
	return 0;
	
}


你可能感兴趣的:(C)