有序全排列的题型对比,例如硬币问题和整数分解问题
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;
}
题目二:用递归实现,显示用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;
}
相关文章推荐
- 南邮 OJ 1219 整数因子分解问题
- 用java语言实现 将输入的正整数分解质因数。例如:输入90,打印出90=5*3*3*2。
- 网易面试题之小易是一个数论爱好者,并且对于一个数的奇数约数十分感兴趣。一天小易遇到这样一个问题: 定义函数f(x)为x最大的奇数约数,x为正整数。 例如:f(44) = 11. 现在给出一个N,需要求
- 对一个5位数的任意整数,求出其降序数。例如,整数是82319,则其降序数是98321。算法提示:将整数的各位数分解到一维整型数组a中,再将a数组中的元素按降序排序,最后输出a数组元素值。
- 正整数分解问题.
- 有序的整数划分,青蛙跳台阶问题 MATLAB
- 整数的素数和分解问题
- 整数因子分解问题
- 整数的素数和分解问题
- 网易面试题之小易是一个数论爱好者,并且对于一个数的奇数约数十分感兴趣。一天小易遇到这样一个问题: 定义函数f(x)为x最大的奇数约数,x为正整数。 例如:f(44) = 11. 现在给出一个N,需要求
- 网易面试题之小易是一个数论爱好者,并且对于一个数的奇数约数十分感兴趣。一天小易遇到这样一个问题: 定义函数f(x)为x最大的奇数约数,x为正整数。 例如:f(44) = 11. 现在给出一个N,需要求
- 0048算法笔记——【随机化算法】拉斯维加斯随机化算法求解整数因子分解中的因子分割问题
- sdut-1722整数因子分解问题
- 0048算法笔记——【随机化算法】拉斯维加斯随机化算法求解整数因子分解中的因子分割问题
- 整数因子分解问题
- (2)int A[nSize],其中隐藏着若干0,其余非0整数,写一个函数int Func(int* A, int nSize),使A把0移至后面,非0整数移至数组前面并保持有序,返回值为原数据中第一个元素为0的下标。(尽可能不使用辅助空间且考虑效率及异常问题,注释规范且给出设计思路)
- akoj-1048-求某一整数序列的全排列问题
- 整数分解问题(二)
- 网易面试题之小易是一个数论爱好者,并且对于一个数的奇数约数十分感兴趣。一天小易遇到这样一个问题: 定义函数f(x)为x最大的奇数约数,x为正整数。 例如:f(44) = 11. 现在给出一个N,需要求
- 整数因子的分解问题--java