计蒜客,https://nanti.jisuanke.com/t/T1248。
洛谷,https://www.luogu.com.cn/problem/P2404。
我的OJ,http://47.110.135.197/problem.php?id=5255。
对于任意大于 1 的自然数 n,总是可以拆分成若干个小于 n 的自然数之和。
现请你编写程序求出 n 的所有拆分。
输入文件共一行,包含一个自然数,即要拆分的自然数 n(1≤n≤20)。
输出文件有若干行,每行包含一个等式,即代表一种可行的拆分(格式与顺序参见样例)。
5
5=1+1+1+1+1
5=1+1+1+2
5=1+1+3
5=1+2+2
5=1+4
5=2+3
将 n 分解为若干个自然数之和,按字典序排列。一个 DFS 模板题。
输入了一个自然数 n,要求分解为若干个自然数之和。自然最长的可能就是 n 个 1 的和,因此我们需要一个数组来保存这些自然数,数组长度只需要为 n 即可。可以参考如下方法定义输出数组:
const int MAXN = 20+2;
int a[MAXN];//dfs方案数组
我们知道最终所有自然数的和为 n,因此在编写 DFS 函数的时候:
1、我们至少需要一个参数,用来表示当前已经加到多少了。
2、需要一个参数表示,数组当前的长度。
3、需要告诉 DFS 程序,我们现在从哪个自然数开始加。
因此,我们可以设置如下的 DFS 函数,至少需要 3 个参数:
/*
第一个参数:数组内数累加和
第二个参数:当前数组长度
第三个参数:当前搜索的开始数据
*/
void dfs(int sum, int len, int start)
有人输出参数,下面我们来分析 DFS 函数内部如何实现。我们肯定用递归来实现 DFS。
1、递归出口条件
既然递归,肯定需要一个出口条件,否则就会变成死循环递归。自然可以很清楚的知道,递归的出口是我们累加和达到了 n。
2、数据处理
套用 DFS 的模板,尝试所有可能。先进一步,递归调用下一个状态;递归结束后,退一步。
这里,我们需要解决的问题是自然数累加为 n,因此,我们可以使用一个循环来遍历所有自然数可能。代码类似如下
for (int i=1; i
为什么是小于 n,而不是小于等于 n 呢?自己思考一下,提示,我们是加法,而且要求是自然数加法。
#include
using namespace std;
const int MAXN = 20+2;
int a[MAXN];//dfs方案数组
int n;//由于输出需要用到n,所以使用全局变量,否则可以不全局
/*
第一个参数:数组内数累加和
第二个参数:当前数组长度
第三个参数:当前搜索的开始数据
*/
void dfs(int sum, int len, int start) {
if (n==sum) {
//已经累加到n
cout << n << "=" << a[0];
for (int i=1; i=start) {
a[len]=i;
len++;
dfs(sum+i, len, i);
len--;
}
}
}
int main() {
cin >> n;
//当前累加和为0
//当前数组长度为0
//当前从1开始尝试
dfs(0,0,1);
return 0;
}