题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1028
思路分析:该问题要求求出某个整数能够被划分为多少个整数之和(如 4 = 2 + 2, 4 = 2 + 1 + 1),且划分的序列 2, 2 或者 2, 1, 1为单调非递增序列;
使用动态规划解法:假设dp[i][j]表示整数i被划分的序列中最大值不超过j的所有的可能,则使用类似于0-1背包的思考方法;
(1)如果i == j,则dp[i][j] = dp[i][j-1] + 1;
(2)如果i > j,则根据整数i被划分的序列中是否有数值 j 分为两种情况:如果序列中含有数值j,则所有和为i - j且最大值不超过j-1的序列加上值 j即可构成和为i的序列;
如果不含有j,则可能的所有不含有数值j且和为i的可能的序列数为 dp[i][j-1]个;
综上:j > i时,dp[i][j] = dp[i][i]; j = i时,dp[i][j] = dp[i][j-1] + 1; j < i时,dp[i][j] = dp[i-j][j-1] + dp[i][j-1];
代码如下:
#include <cstdio> #include <cstring> #include <iostream> const int MAX_N = 120 + 20; long long dp[MAX_N][MAX_N]; void Solve() { dp[0][0] = 1; for (int i = 0; i < MAX_N; ++ i) { for (int j = 1; j < MAX_N; ++ j) { if (j > i) dp[i][j] = dp[i][i]; else if (i == j) dp[i][j] = dp[i][j-1] + 1; else dp[i][j] = dp[i][j-1] + dp[i-j][j]; } } } int main() { int number = 0; Solve(); while (scanf("%d", &number) != EOF) printf("%d\n", dp[number][number]); return 0; }