问题描述
可将正整数n表示成系列正整数之和:n= n1 + n2 +…+ nk。其中ml ≥ n2 ≥ … ≥ nk ≥ 1,k ≥ 1。整数划分问题:求正整数n的不同的划分个数,以及所有划分。
输入形式
正整数n.
输出形式
第一行输出正整数n的不同的划分个数,后续行每行输出其中一个划分。
样例输入
6
样例输出
1 1
6
5 1
4 2
4 1 1
3 3
3 2 1
3 1 1 1
2 2 2
2 2 1 1
2 1 1 1 1
1 1 1 1 1 1
样例说明
按照定的规则输出结果,每行输出的一个划分,要满足条件n1 ≥ n2 ≥ … ≥ nk ≥ 1,k ≥ 1,并且大的正整数n1,n2,… 先输出。
数据规模
1 ≤ n ≤ 10
问题分析
整数划分问题可以采用递归的方式解决。对于一个整数正整数m,要找到所有符合的n1+n2+n3…(n1≥n2≥n3…)。
我们可以先确定第一个数n1,范围当然是从m到1逐步遍历。确定完n1后,剩下的问题就相当于找到 min{m-n1 , n1} 的所有划分,这时候递归的方法就已经很明显了。
由于要先输出总共的划分数num,我们可以利用二维数组或者vector容器来记录每一次找到的划分,在算法结束之后进行输出。
我们以m=4为例,最多递归深度为4。
如上表所示,m=4,选择用vector堆来记录每一次的划分。可能成为划分的数则入堆,成功找到划分后再出堆寻找新的划分可能。
算法伪代码
vector<int> point;//在递归算法中记录每一步的操作
vector<vector<int>> result;//记录所有的划分结果,当point中的记录就是一个划分时,将此时的point记录为result的一个元素
sum=0;//记录划分数
void Classify(int N, int now, int num)
{
//N是题目中的要找划分的数
//now是当前层次函数中要寻找的划分
//num是当前划分累计的大小,用来与N比较大小判断是否找到划分
for( i从now到1遍历)
{
num加上i ;
i 入栈 point;
if( num等于N,代表找到一个划分 )
{
point入栈result;
总数sum加一;
i出栈;
num减去i;
continue;继续寻找
}
Classify(N, min( N-num, i ), num);
i出栈;
num减去i;
}
}
完整程序
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
vector<int> point;
vector<vector<int>> result;
int sum = 0;
void Print(vector<vector<int>> result)
{
int i, j;
for (i = 0; i < result.size(); i++)
{
for (j = 0; j < result[i].size(); j++)
cout << result[i][j] << ' ';
cout << endl;
}
}
void Classify(int N, int now, int num)
{
int i = now;
for (; i >= 1; i--)
{
num += i;
point.push_back(i);
if (num == N)
{
result.push_back(point);
sum++;
point.pop_back();
num -= i;
continue;
}
Classify(N, min(N - num, i), num);
point.pop_back();
num -= i;
}
}
int main()
{
int N;
cin >> N;
Classify(N, N, 0);
cout << sum << endl;
Print(result);
system("pause");
}