题目
题目描述
任何一个大于1的自然数n,总可以拆分成若干个小于n的自然数之和。现在给你一个自然数n,要求你求出n的拆分成一些数字的和。每个拆分后的序列中的数字从小到大排序。然后你需要输出这些序列,其中字典序小的序列需要优先输出。
输入格式
输入:待拆分的自然数n。
输出格式
输出:若干数的加法式子。
输入输出样例
输入 #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
说明/提示
用回溯做。。。。
n≤8
题解
1. 首先明确,这是一个关于DFS的回溯问题,DFS的特征是会把所有情况都考虑出来,所有用DFS。回溯就是将走过的路径打印出来。
2. 怎么用DFS,这个题目中的DFS是用来分解自然数的,我的做法是运用DFS从1开始加,一直加到加数(sum)等于输入的n,判断一下sum==n。
3.要注意的是要回溯路径,这时候需要一个t(t代表一共加了几次)和一个数组x[](注意这个数组一定要是全局变量)来记录一下每一步的被加数,用一个pri函数打印,要向这个pri函数中传递的参数是最后的t(就是满足一次sum==n条件时的最后t的值)的值。
4.DFS的限制条件,就是必须要是一个加法,要满足加法的条件,被加数的个数要大于1,这个就与t的值有关了,t的初始值为0,当t>1是才能成为加法,所以再sum==n的条件后面还要加一个条件t>1。
5.我写的DFS中有三个形参,分别代表从x开始加,加数和,t上面已经做了解释。
6.每加一次要用x[]记录一下,当前所加的数的值,还要用sum记录当前的加数和。
7.每次调用DFS后返回时要取消记录。
代码如下
#include"stdio.h"
#include"string.h"
int n;
int b[8];
void pri(int i)
{
int t;
for(t=0;t<i;t++)
{
if(t==0)
printf("%d",b[t]);
else
printf("+%d",b[t]);
}
printf("\n");
}
void dfs(int x,int sum,int t)//x表示从几开始加,sum表示加数和
{
int i;
if(sum==n&&t>1)
{
pri(t);//记录一下总数
return;
}
for(i=x;i<=n-sum;i++)//保证加数,小于或者等于n
{
b[t]=i;
sum+=i;
// printf("x=%d sum=%d t=%d\n",x,sum,t);
dfs(i,sum,t+1);//取消记录
sum-=i;
}
}
int main()
{
scanf("%d",&n);
dfs(1,0,0);
return 0;
}