题目描述
任何一个大于 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;
}
后记
没啥后记说了,点个赞吧!