计蒜客题解——T1248:自然数拆分

题目相关

题目链接

计蒜客,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方案数组

DFS 函数设计

我们知道最终所有自然数的和为 n,因此在编写 DFS 函数的时候:

1、我们至少需要一个参数,用来表示当前已经加到多少了。

2、需要一个参数表示,数组当前的长度。

3、需要告诉 DFS 程序,我们现在从哪个自然数开始加。

因此,我们可以设置如下的 DFS 函数,至少需要 3 个参数:

/*
第一个参数:数组内数累加和
第二个参数:当前数组长度
第三个参数:当前搜索的开始数据
 */
void dfs(int sum, int len, int start)

DFS 函数内部实现

有人输出参数,下面我们来分析 DFS 函数内部如何实现。我们肯定用递归来实现 DFS。

1、递归出口条件

既然递归,肯定需要一个出口条件,否则就会变成死循环递归。自然可以很清楚的知道,递归的出口是我们累加和达到了 n。

2、数据处理

套用 DFS 的模板,尝试所有可能。先进一步,递归调用下一个状态;递归结束后,退一步。

这里,我们需要解决的问题是自然数累加为 n,因此,我们可以使用一个循环来遍历所有自然数可能。代码类似如下

for (int i=1; i<n; i++) {
    判断条件是否成立 {
        记录这个自然数
        进一步
        递归调用dfs函数
        退一步
    }
}

为什么是小于 n,而不是小于等于 n 呢?自己思考一下,提示,我们是加法,而且要求是自然数加法。

AC 参考代码

#include <iostream>

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<len; i++) {
            cout << "+" << a[i];
        }
        cout << endl;
        return;
    }

    //搜索
    for (int i=1; i<n; i++) {
        if (sum+i<=n && 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;
}
发布了234 篇原创文章 · 获赞 289 · 访问量 107万+

猜你喜欢

转载自blog.csdn.net/justidle/article/details/104876458
今日推荐