题目描述:
一个整数N(N > 1)可以拆分成若干个大于等于1的自然数之和,请你输出所有不重复的拆分方式。
若满足集合A=B,则称这两种拆分方式是重复的。
例如 5 = 3 + 2 和 5 = 2 + 3, 就是重复的拆分方式。
输入格式:
一个正整数N(1 ≤ N ≤ 52)
输出格式:
按照拆分方案的字典序由小到大,输出所有方案,请参考输出样例
输入样例:
6
输出样例:
6=1+1+1+1+1+1 6=1+1+1+1+2 6=1+1+1+3 6=1+1+2+2 6=1+1+4 6=1+2+3 6=1+5 6=2+2+2 6=2+4 6=3+3 6=6
算法思想:
(参考洛谷P2404 自然数的拆分问题)
以拆分4为例,说明拆分的方法:
对于每个分支,父节点<=子节点<=当前被拆分数(为了满足字典序要求)
例如:4被拆分为1后,被拆分数变为3;4被拆分为1+1后,被拆分数变为2。
参考代码:
#include<bits/stdc++.h>
using namespace std;
int a[52]={1},n;
void print(int num){
cout << n << "=";
for(int i=1;i<num;i++){
cout << a[i] << "+";
}
cout << a[num] << endl;
}
void dfs(int cur,int num){
//cur为当前被拆分数, num为当前分支子节点的个数
for(int i=a[num-1];i<=cur;i++){//父节点<=子节点<=当前被拆分数
if(i==n) continue;//拆分数是被拆分数自身
a[num]=i;//保存当前拆分的数i
cur-=i;//拆分出i后,被拆分数进行更新
if(cur==0)//拆分结束,输出结果
print(num);
else//递归,进行下一次拆分
dfs(cur,num+1);
cur+=i;//回溯,刚才减去i,现在再加上i,分析其他情况
}
}
int main(){
std::ios::sync_with_stdio(false);
//cout超时,这里加速一下
cin >> n;
dfs(n,1);
cout << n << "=" << n;
return 0;
} 代码分析:
可能是因为刚接触到回溯法,更可能是因为自己还太弱了(QAQ),看了好多大佬自然数拆分(回溯法)的题解也没完全弄懂逻辑,自己用数据模拟了几遍才逐渐清楚。
另外,这道题和洛谷上的还有些区别,可以看看洛谷上的题解找找思路。
题解 P2404 【自然数的拆分问题】
P2404 自然数的拆分问题

京公网安备 11010502036488号