P2404 自然数拆分问题

题目描述

任何一个大于 1 的自然数 n,总可以拆分成若干个小于 n 的自然数之和。现在给你一个自然数 n,要求你求出 n 的拆分成一些数字的和。每个拆分后的序列中的数字从小到大排序。然后你需要输出这些序列,其中字典序小的序列需要优先输出。

输入格式

输入:待拆分的自然数 n。

输出格式

输出:若干数的加法式子。

样例 #1

样例输入 #1

7

样例输出 #1

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

提示

数据保证,1 <= n <= 8。

思路

深搜的变形题,只要按照一层一层的顺序挨个深搜枚举,就可以过啦。但是注意要进行一点小小的剪枝,以防超时;另外一个就是要判断当前是否是多个(最少2个)组成的表达式,否则不能输出(就比如一个7)。

如何实现深搜枚举?

暴力深搜,必然是for语句搭配输出语句深层嵌套啦。首先定义函数体,其中函数列表内要有三个变量:n(要求拆的数字,同时做倒计功能),last(标记上个枚举的数字是什么)和step(标记当前枚举到第几个数字,同时做数组下标)。接下来分为两部分:

  • 枚举部分,是从last开始一直到n(应为n比较小,就不必在这里进行优化剪枝)暴力枚举,存入数组中。每存一次就要dfs一次。

  • 在枚举部分前面是判断输出部分。首先判断如果last已经大于n并且n!=0,也就是还没枚举完,立刻return。再接着判断如果n等于0并且step大于1(因为表达式最少两个数字)就输出。

深搜枚举代码实现

void f(int n,int last,int step)
{
    if(last>n&&n!=0)return;
    if(n==0&&step>1)
    {
        for(int i=0;i<step-1;i++)cout<<a[i]<<"+";
        cout<<a[step-1]<<endl;
    }
    for(int i=last;i<=n;i++)
    {
        a[step]=i;
        f(n-i,i,step+1);
    }
    return;
}

AC代码

#include<iostream>
using namespace std;
const int N=1e6+10;
int n,ans,a[N];
void f(int n,int last,int step)//深搜
{
    if(last>n&&n!=0)return;//剪枝优化
    if(n==0&&step>1)
    {
        for(int i=0;i<step-1;i++)cout<<a[i]<<"+";//输出表达式
        cout<<a[step-1]<<endl;
    }
    for(int i=last;i<=n;i++)//逐个枚举
    {
        a[step]=i;
        f(n-i,i,step+1);//下一层深搜
    }
    return;
}
int main()
{
    int n;
    cin>>n;
    f(n,1,0);
    return 0;
}

后记

没啥后记说了,点个赞吧!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值