题目
将正整数n 表示成一系列正整数之和,n=n1+n2+…+nk, 其中n1>=n2>=…>=nk>=1 ,k>=1 。
正整数n 的这种表示称为正整数n 的划分。正整数n 的不同的划分个数称为正整数n 的划分数。
输入
标准的输入包含若干组测试数据。每组测试数据是一个整数N(0 < N <= 50)。
输出
对于每组测试数据,输出N的划分数。
样例输入
5
样例输出
7
提示
5, 4+1, 3+2, 3+1+1, 2+2+1, 2+1+1+1, 1+1+1+1+1
思路
用动态规划做类似背包问题,dp(n, i)的值为选i (dp(n-i, i))和不选i (dp(n, i-1)) 之和,当然这是在n >= i 时的情况。当 n = 0 时,只有n个0相加这一种方案,故dp(n, i) = 1。当i = 0 时,划分不包含0,也就是不会有一种划分会加0,故dp(n, i) = 0。最后一种情况,当n < i 时,dp(n, i) = dp(n, i-1)。
用递归做也是这四种情况,只不过用的是递归函数,不是dp数组。
dp代码
#include<iostream>
#include<cstring>
using namespace std;
const int maxn = 1000 + 10;
int dp[maxn][maxn], n, m;
void sovle() {
dp[0][0] = 1;
for (int i = 1; i <= n; i++) {
for (int j = 0; j <= n; j++) {
if (j - i >= 0) {
dp[i][j] = dp[i][j - i] + dp[i - 1][j];
}
else dp[i][j] = dp[i - 1][j];
/*打表调试
cout << dp[i][j] << " ";
if (j == n)
cout << endl;
*/
}
}
}
int main()
{
while (cin >> n) {
memset(dp, 0, sizeof(dp));
sovle();
cout << dp[n][n] << endl;
}
return 0;
}
递归代码
#include <iostream>
using namespace std;
int ways(int n, int i)
{
if (n == 0)
return 1;
if (i == 0)
return 0;
if (i <= n)
return ways(n - i, i) + ways(n, i - 1); //用i和不用i的情况。i可以重复使用
else
return ways(n, i - 1);
}
int main()
{
int n;
while (cin >> n)
cout << ways(n, n) << endl;
return 0;
}