程序设计与算法(二)简单的整数划分问题

题目
将正整数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;
}
发布了26 篇原创文章 · 获赞 11 · 访问量 2303

猜你喜欢

转载自blog.csdn.net/qq_41731507/article/details/102171866
今日推荐