面试100题系列之14从1到n中随意取几个数,使其和为m

来源:互联网 发布:菲律宾globe网络制式 编辑:程序博客网 时间:2024/05/16 08:41
1、题目描述:输入两个整数n和m,从数列1,2,3.......n 中随意取几个数,这里同一个数不能重复取,使其和等于m,要求将其中所有的可能组合列出来。
解题思路:典型的0-1背包问题,每一个数字都有两种状态,取或者不取。最简单的就是用递归求解。这里的遍历顺序是从n到1,这样比较好判断递归的出口,当然也比较方便剪枝。核心代码如下,有没有觉得很漂亮:
//找到1~Num中和等于Sum的所有组合void FindCombination(int *arr, int Index, int Sum, int Num){if(Sum < 1 || Num < 1)return;if(Sum < Num)Num = Sum;if(Sum == Num || Sum == 1){arr[Index++] = Sum;Print(arr, Index);--Index;return;}//不取当前最大值NumFindCombination(arr, Index, Sum, Num - 1);arr[Index++] = Num;//取当前最大值NumFindCombination(arr, Index, Sum - Num, Num - 1);}
2、题目扩展,上面一个题要求每一个数字只能取一次,要是每个数字可以随便取多少次,那这样的组合有多少种呢?这种情况的数据很大,所以不需要输出具体的组合,只需要给出种类的数量就可以了,博客钱币兑换问题就是用这个方法求解的。这种情况下就用母函数来求解。关于母函数的相关知识,有时间了我再补充上来,如果大家不懂,可以先留着,下次再来看。关于这种题目有几种应用情况,以前写过的,不过代码不知道丢到哪里了,下次补上:
*每一种数字的数量不限,也就是可以无限次的取。
*每一种数字都给定一个数量,只能在数量范围之内取。这种情况就类似于任意一个多项式的展开。
核心代码如下:
//允许数字重复,找出所有1~Num组成的和为Sum的数int GetNumOfSum(int Sum, int Num){if(Sum < 1 || Num < 1)return 0;if(Num > Sum)Num = Sum;int c1[N];int c2[N];int i,j,k;for(i = 0; i <= Sum; ++i)c1[i] = 1;memset(c2, 0, (Sum + 1) * sizeof(int));for(i = 2; i <= Num; ++i){//遍历所有的因子for(j = 0; j <= Sum; ++j){//遍历所有的指数for(k = 0; k + j <= Sum; k += i){//用当前指数去乘当前因子组成的多项式c2[k + j] += c1[j];}}memcpy(c1, c2, (Sum + 1) * sizeof(int));memset(c2, 0, (Sum + 1) * sizeof(int));}return c1[Sum];}
3、最后给出变量的定义和main函数的调用。
#include<stdio.h>#include<string.h>const int N = 30;//打印数组void Print(int *arr, int nLen){if(!arr || nLen < 1)return;for(int i = 0; i < nLen; ++i)printf("%d ", arr[i]);printf("\n");}int main(){int arr[N];int n,m;while(scanf("%d %d", &n, &m) != EOF){//FindCombination(arr, 0, m, n);printf("可重复,则一共有%d种\n", GetNumOfSum(m, n));}return 0;}




原创粉丝点击