最新文章
这里会显示最新的几篇文章摘要。
记录生活,分享知识,与你一起成长。
这里会显示最新的几篇文章摘要。
给定一个自然数N,要求把N拆分成若干个正整数相加的形式,参与加法运算的数可以重复。
注意:
一个自然数N。(1≤N≤4000)
输入一个整数,表示结果。
7
14
【举例】按题意,数字5有6种不同的拆分方案,分别是
1+1+1+1+1
1+1+1+2
1+1+3
1+4
1+2+2
2+3
我怎么就找不到正确的状态呢???
这个问题是整数拆分的变形,可以用动态规划(DP)来解决。我们可以用完全背包的思想来理解它。
对于给定的 N,要求将 N 拆分成至少两个正整数之和,且拆分顺序不影响结果(即 1+2 和 2+1 视为同一种方案)。
可以转换为:
设 dp[i][j] 表示使用数字 1 到 i 进行拆分,得到和为 j 的方案数。
状态转移方程
i,则 dp[i][j] = dp[i-1][j]i,则 dp[i][j] = dp[i][j-i]综上:
[
dp[i][j] = dp[i-1][j] + dp[i][j-i]
]
解释:
dp[i-1][j] 表示不使用 i 进行拆分的方案数。dp[i][j-i] 表示选取 i 之后,剩下的 j-i 仍然需要拆分,继续使用 i 及更小的数。dp[i][0] = 1,表示拆分成 0 的方案数只有一种,即空集。dp[0][j] = 0,没有数可用时,不能拆分。我们可以用一维数组优化 DP,把 dp[i][j] 压缩成 dp[j](完全背包思想)。
#include <iostream>
using namespace std;
const int MOD = 2147483648;
const int N = 4005;
int dp[N];
int main() {
int n;
cin >> n;
dp[0] = 1; // 拆分成 0 的方案只有一种
for (int i = 1; i < n; i++) { // 遍历 1~(N-1) 作为可选数
for (int j = i; j <= n; j++) { // 这里采用正序遍历,类似完全背包
dp[j] = (dp[j] + dp[j - i]) % MOD;
}
}
cout << dp[n] << endl;
return 0;
}