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

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;
	}
	//不取当前最大值Num
	FindCombination(arr, Index, Sum, Num - 1);
	arr[Index++] = Num;
	//取当前最大值Num
	FindCombination(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;
}




  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值