求正整数n所有可能的和式的组合

题目:

给定一个数字n,求解出所有和为n的整数组合,要求组合按照递增方式展示,而且唯一。

分析:

最初看到这个题,没有什么特别好的思路,后来看了下别人的帖子,其实问题也没那么难,采用递归的方式进行求解,比如我们需要计算和为4的所有组合,我们首先将小于等于4的所有数字列出来

1,2,3,4

首先选取第一个数字,我们选取1,这时候,余下的和为(4-1),我们继续从1,2,3,4中选择,如此递归下去

第二次,我们选择1后面的数字,也就是2,作为第一个数字,余下的和为(4-2),我们继续从2,3,4中选择和为2的组合,注意,这里是从2,3,4中选取,而不是1,2,3,4中选取,如果采用后者方式,我们得到的结果会存在重复组合,比如1,1,2和2,1,1。

代码如下:

/*
 * combinationForNumber.cpp
 *
 *  Created on: 2012-10-19
 *      Author: happier
 */
#include <iostream>
#include <string.h>
#include <cstdio>
#include <cstdlib>
using namespace std;

#define MAX_VALUE	20
int next[MAX_VALUE] = { 0 };	//可以理解成一个链表,next[i]表示i数后面跟着的数字

/*
 * 递归进行求解
 * @nSum 目标和
 * @pData 保存已经存在的数字
 * @nDepth 记录当前已经保存数据的个数
 */
void SegNum(int nSum, int* pData, int nDepth)
{
	if (nSum < 0)
		return;

	//如果已经符合要求,开始输出
	if (nSum == 0)
	{
		for (int j = 0; j < nDepth; j++)
			cout << pData[j] << " ";
		cout << endl;

		return;
	}

	//这里有一个小trick,如果要求呈现递增,采用第一种赋值方式
	//如果可以是重复的,即非递增方式,采用第二种赋值
	int i = (nDepth == 0 ? next[0] : pData[nDepth - 1]);
	//int i = next[0];
	for (; i <= nSum;)
	{
		pData[nDepth++] = i;
		SegNum(nSum - i, pData, nDepth);
		nDepth--;	//递归完成后,将原来的数据弹出来,并且去链表中的下一个数字

		i = next[i];
	}

	return ;
}

void ShowResult(int array[], int nLen)
{
	next[0] = array[0];
	int i = 0;
	for (; i < nLen - 1; i++)
		next[array[i]] = array[i + 1];	//下一个可选数字大小
	next[array[i]] = array[i] + 1;	//next[MAX_VALUE]大于MAX_VALUE,一个小trick,避免了很多比较

	int* pData = new int[MAX_VALUE];
	SegNum(MAX_VALUE, pData, 0);
	delete[] pData;
}

int main()
{
	int* array = new int[MAX_VALUE];
	for (int i = 0; i < MAX_VALUE; i++)
	{
		array[i] = i + 1;
	}
	//找零钱测试
	ShowResult(array, MAX_VALUE);

	//system("pause");
	return 0;
}

代码转自: http://blog.csdn.net/wumuzi520/article/details/8046350,我添加了一些注释,注意在这个代码中,作者用next[]数组来模拟链表

总结:

如果没有很好的思路,我们采用递归方式,分而治之,将问题一步一步减小。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 这是一个比较复杂的问题,需要用到递归算法来解决。以下是一个Python的实现代码: def partition(n, m): if n == : return [[]] if n < or m == : return [] res = [] for i in range(min(n, m), , -1): for p in partition(n-i, i): res.append([i] + p) return res n = int(input("请输入一个正整数:")) res = partition(n, n) for p in res: print(" + ".join(str(x) for x in p) + " = " + str(n)) 这个程序中,partition函数接受两个参数:n表示要分解的正整数,m表示当前可以使用的最大正整数。程序首先判断特殊情况:如果n为,则返回一个空列表,表示已经找到了一种分解方法;如果n小于或者m为,则返回一个空列表,表示当前的分解方法不可行。否则,程序遍历从m到1的所有正整数i,对于每个i,递归调用partition函数,n-i的所有分解方法,并将i加入到每个分解方法的开头,得到新的分解方法。最后,程序返回所有的分解方法。 在主程序中,程序读入一个正整数n,然后调用partition函数所有的分解方法,并输每个分解方法。输时,程序将每个分解方法转换成字符串,用加号连接起来,然后输等于n的表达。 ### 回答2: 正整数分解问题是一个经典的组合问题,也是计算机算法设计中的一个重要问题。它涉及到组合数学和动态规划等计算机科学领域的知识。在计算机算法设计中,通过对原问题进行递归分解和动态规划优化,可以有效地解决正整数分解问题。 解决正整数分解问题的基本思路是:将正整数n拆分成两个正整数m和n-m,并在m和n-m之间递归解,直到拆分到只有一个数时,记录下分解的结果,以此来完成对原问题的解。这种方法是分治算法的典型应用,通常可以通过树形递归来实现。 除此之外,我们还可以采用动态规划方法来解决正整数分解问题。具体方法是:设S(n)为正整数n的所有分解方法总数,则有以下递推: S(n) = S(n-1) + S(n-2) + ... + S(1) 这个递推的意义是,对于正整数n,它可以分解成n-1和1,也可以分解成n-2和2,以此类推,直到最后可以分解成1和n-1。因此,我们可以通过累加S(1)到S(n-1)的值,来得S(n)的值。 以上是两种比较常用的解题方法。总之,对于这个问题,需要灵活运用数学知识和计算机算法实现,才能得到令人满意的解答。 ### 回答3: 问题描述: 给定一个正整数n,现在需要编程所有可以将n分解成若干个正整数相加的方案。 分析: 为了所有的分解方案,我们可以采用递归的思想。具体地,对于当前的n,我们从1开始枚举每个小于等于n的正整数i,然后递归解剩余的n-i。如果n-i等于0,说明已经找到了一种分解方案。否则,继续从n-i开始分解。 代码实现: 下面是用C++实现的代码。注意,在输时,我们需要将分解结果按照非递减的顺序输,避免重复。 ```cpp #include <iostream> #include <vector> #include <algorithm> using namespace std; void dfs(int n, vector<int>& path) { if (n == 0) { for (int i = 0; i < path.size(); i++) { if (i > 0) cout << " "; cout << path[i]; } cout << endl; return; } for (int i = 1; i <= n; i++) { if (path.empty() || i >= path.back()) { path.push_back(i); dfs(n - i, path); path.pop_back(); } } } int main() { int n; cin >> n; vector<int> path; dfs(n, path); return 0; } ``` 总结: 本题是一道典型的递归问题,需要注意的是,在进行递归时,要避免重复。具体地,在每次递归时,只枚举大于等于前一个数字的数,这样可以避免重复,也保证了分解结果按照非递减顺序输

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值