您的位置:首页 > 其它

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

2018-03-16 15:26 603 查看
题目一:输入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;i<top;i++){

printf("%d",stack[i]);
if(i!=top-1) printf("+");

}

printf("\n");
return ;
}
if(sum>n) return ;                    //若大于n,则直接返回
for(int i = index;i>=1;i--){

sum = sum+i;                //sum为全局变量,起到求和目的
stack[top++] = i;
devi(i);                    //递归的进行下一次的填数,传入i,保证了有序性
sum -=i;                    //由下一层返回到这一层,将填入的数减去,并弹出
top--;
                            //i--尝试填入较小的数
}

}好,让我们看看全部的代码:#include<cstdio>

//输入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;i<top;i++){

printf("%d",stack[i]);
if(i!=top-1) printf("+");

}

printf("\n");
return ;
}
if(sum>n) 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 <cstdio>

//用递归实现,显示用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;i<top;i++){

printf("%d",stack[i]);
if(i!=top-1) printf("+");

}
printf("\n"); */
return ;
}
if(sum>n) 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 <cstdio>
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;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐