版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/bleedingfight/article/details/81950703
问题来自牛客
输入两个整数 n 和 m,从数列1,2,3…….n 中随意取几个数,使其和等于 m ,要求将其中所有的可能组合列出来 。
解决思路:
从1-n
找到数字之和等于m,那么如果我先找到一个数1,剩下的任务就是在2~m-1
找到求和等于m-1
就够了。那如果找到第2个数2
求和小于(找到的1+2求和为3
)m,接下来找3,继续这样往下找,如果求和大于m则不合适,说明组合不合理,这时候需要退回,说明1-2
组合不合适,这时需要尝试新的组合比如1-3
反复如此直到计算结束。
以m=5,n=5
为例,
- 开始,1入栈,接下来在2-5之间找到数字之和为
4(m-1=5-1)
- 2入栈,接下来在
3-5
之间找到数字子和为2的数字,因为接下来的数字至少都等于3,所以肯定找不到,于是2出栈 - 3进栈,接下来的任务是在
4-5
之间找到数字使得其和为1,显然找不到,退栈。 - 4进栈,这时候满足求和为5,于是输出。不用直接到5了,因为5,m就为-1了。于是1退栈。
- 2进栈,这时候需要在
3-5
之间找到数字使得和为3。 - 3进栈,这时候找到,直接打印,退栈(2,3)。
- 3进栈,需要在
4-5
之间找到能够使得和为(2),明显找不到,退栈。剩下依次。 - …
- 5入栈,接下来需要在剩下的数字中找到0,打印结果。
下面的代码来自牛客,作者没有注明,无法引用(仅修改打印部分)。
#include <iostream>
#include <vector>
using namespace std;
void help(int n,int m,vector<int> &v,int begin)
{
if(m == 0)
{
for(auto i:v)
{
cout<<i<<" ";
}
cout<<"\n";
}
for(int i=begin;i<=m&&i<=n;i++)
{
v.push_back(i);
help(n,m-i,v,i+1);
v.pop_back();
}
}
int main() {
int n = 5;
int m = 5;
vector<int> v;
// cin>>n>>m;
help(n,m,v,1);
return 0;
}
代码中vector作为栈使用用来存储可用的数据,打印逻辑是碰到m为0的时候打印。
下面是Python实现:
def get_sum(n,m,l,begin_num):
if m == 0:
for i in l:
print(i,end=" ")
print()
else:
for i in range(begin_num,m+1):
if i<=m and i<=n:
l.append(i)
get_sum(n,m-i,l,i+1)
l.pop()
def main():
# n,m = input().split()
# n = eval(n)
# m = eval(m)
m = 8
n = 10
get_sum(n,m,[],1)
if __name__ == '__main__':
main()