大家好,今天小编给大家带来的这个问题是一个比较重要的知识点的运用。
先看题目:
小T的老师让他编一个程序来判断正整数n中能被分成k个整数的方法(1 <= k <= n <= 20)
为了不让小T误解,老师举了一个例子:
输入:6 3 输出: 1 1 4
1 2 3
2 2 2
老师最后还说,1 4 1和4 1 1这种和1 1 4一样是同一种分法。
小T尝试了很久都没法编出来,你能帮帮小T么?
——————————————不华丽的蒟蒻解法分割线——————————————
好的,我们看这道题,发现用正常方法很难推出,因为循环次数并不同,而且假设输入20 20,需要整整二十次循环,想想都不靠谱好吧[狗头]。
这时我们需要用一个方法叫做递归,详细见链接:递归算法。
直接开编,我们需要一个dfs函数,注意要用void,至于里面接下来会详细描述。
void dfs(int step,int sum){
if(sum > n) return;//当累加总和sum大于n时,可以直接跳过
if(step > k){//当累加个数step大于k时,开始判断
if(sum == n){//这时当sum=n时就代表这种方式可以
for(int i = 1;i <= k;i++){
cout << a[i] << " ";//直接打印
}
cout << endl;
}
return;//跳出
}
for(int i = a[step - 1];i <= n;i++){//这里的a[step-1]是避免出现重复分法
a[step] = i;
dfs(step + 1,sum + i);//这个是函数的自调用,其实就是把每一种情况都判断了一遍
}
}
好的,大概就是这样。
接下来是主函数main:
int main(){
cin >> n >> k;//简单输入
a[0] = 1;//[易错点]
dfs(1,0);//初值step是第一个数,sum还没有数,为0
return 0;
}
解释一下这里的“易错点”:
我们这里让a[0] = 1是因为k项中肯定不会有一个值为0,可最开始定义时列表所有项都为0,所以需要让第一项为最小的非0自然数1,这样就解决了类似出现0 1 5、2 0 4这种情况,至于后面为什么不赋值看上面dfs函数的a[step-1],因为a[0] = 1,自然地,a[1]会以a[1-1] = a[0] = 1开始推,a[2]会以a[2-1] = a[1] = a[1-1] = a[0]来推,以此类推。
好了,这样子主体也是成功编好了,加上头文件和定义,完成以下完整代码:
#include<cstdio>
#include<cstring>
#include<iostream>
//上面3个可以用bits/stdc++.h来代替
using namespace std;
int n,k,a[25];
void dfs(int step,int sum){
if(sum > n) return;
if(step > k){
if(sum == n){
for(int i = 1;i <= k;i++){
cout << a[i] << " ";
}
cout << endl;
}
return;
}
for(int i = a[step - 1];i <= n;i++){
a[step] = i;
dfs(step + 1,sum + i);
}
}
int main(){
cin >> n >> k;
a[0] = 1;
dfs(1,0);
return 0;
}
好了,今天分享就到这里,这次的素材真的很难获得,并且编起来也比较麻烦,谢谢大家支持!