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

很多人在面试中会被问到这样的题目,题目的含义是有如下的组合4=1+1+1+1、1+1+2、1+3、2+1+1、2+2。光从题目来看有两种理解:

  1. 将3 = 1 +2 和3 = 2 +1当作不同的组合。这种情况是比较简单的,直接将给定的n递归地分解成(n – 1) + 1当递归求得的结果和我们需要分解的整数n相等,则这次分解就完成了,我们可以把分解的组合输出来,然后返回。一直递归到n不能再分解(也就是分解成了n个1)。

    #include<iostream>
    #include<vector>
    using namespace std;
    //此算法1+2与2+1当成两种不同情况
    void findadd(int sum,int start,int tempsum,vector<int> &v)
    {
    	if(tempsum == sum)
    	{
    		vector<int>::iterator it = v.begin();
    		for(;it!=v.end();it++)
    		{
    			cout<<*it;
    			if(it+1 != v.end())
    				cout<<"+";
    		}
    		cout<<endl;
    		return ;    //找到sum的组合后返回
    	}
    	else if(tempsum > sum) 
    		return ;    //大于sum时也返回
    	//进入递归
    	for(int i=sum;i>0;i--)
    	{
    		v.push_back(i);
    		findadd(sum,i,tempsum+i,v); //注意递归后第二个参数为i,第三个参数为tempsum+i.
    		v.pop_back();
    	}
    }
    
    void add(int sum)
    {
    	int tempsum =0;
    	vector<int> v;
    	findadd(sum,sum,tempsum,v);
    }
    int main()
    {
    	add(5);
    	return 0;
    }
    运行的结果:

    5
    4 + 1
    3 + 2
    3 + 1 + 1
    2 + 3
    2 + 2 + 1
    2 + 1 + 2
    2 + 1 + 1 + 1
    1 + 4
    1 + 3 + 1
    1 + 2 + 2
    1 + 2 + 1 + 1
    1 + 1 + 3
    1 + 1 + 2 + 1
    1 + 1 + 1 + 2
    1 + 1 + 1 + 1 + 1

  2. 如果把将3 = 1 +2 和3 = 2 +1当作相同的组合,这下相对来说比较难点,但是仔细分析,会发现,算法和上面的几乎一样,每次分解的数不再是从n开始,这样可以使得每次分解的数不会超过上一次分解出来的数代码只修改了一个地方就可以实现:

    #include<iostream>
    #include<vector>
    using namespace std;
    
    //此算法1+2与2+1当成相同的情况
    void findadd(int sum,int start,int tempsum,vector<int> &v)
    {
    	if(tempsum == sum)
    	{
    		vector<int>::iterator it = v.begin();
    		for(;it!=v.end();it++)
    		{
    			cout<<*it;
    			if(it+1 != v.end())
    				cout<<"+";
    		}
    		cout<<endl;
    		return ;    //找到sum的组合后返回
    	}
    	else if(tempsum > sum) 
    		return ;    //大于sum时也返回
    	//进入递归<核心>
    	for(int i=start;i>0;i--)    //这里与上一种方法的区别是i=start而不是i=sum,仅此一个区别.
    	{
    		v.push_back(i);
    		findadd(sum,i,tempsum+i,v);
    		v.pop_back();
    	}
    }
    void add(int sum)
    {
    	int tempsum =0;
    	vector<int> v;
    	findadd(sum,sum,tempsum,v);
    }
    int main()
    {
    	add(5);
    	return 0;
    }
    程序运行结果:

    5
    4 + 1
    3 + 2
    3 + 1 + 1
    2 + 2 + 1
    2 + 1 + 1 + 1
    1 + 1 + 1 + 1 + 1

  • 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、付费专栏及课程。

余额充值