13.整数划分 计数类DP

 每种划分方式都是按照从大到小排序的

样例分析:

5有7种划分方式

5 = 5

5 = 4 + 1

5 = 3 + 2

5 = 3 + 1 + 1

5 = 2 + 2 + 1

5 = 2 + 1 + 1 + 1

5 = 1 + 1 + 1 + 1 + 1

解法一:用背包问题的思想

把整数n看做一个容量为n的背包

然后一共有n个物品,每个物品的体积分别是1,2,3,...,n。(也就是n这个数的所有因子)

每种物品可以用无限次,所以是完全背包问题

求恰好装满背包的方案数

状态表示:

集合:dp[i][j]表示从物品1~i中选,总体积恰好为j的选法的集合

属性:数量

状态计算:集合的划分,同背包问题

根据第i个物品选了几个来划分

状态数量:n ^ 2

转移数量:n(粗略估计的,比n小,应该为log n)

时间复杂度:n ^ 3

然后进行优化

 

二维做法

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int N = 1010, mod = 1e9 + 7;
 4 int dp[N][N];
 5 int main() {
 6     int n;
 7     cin >> n;
 8     for (int i = 0; i <= n; i++) { //注意是从0开始
 9         dp[i][0] = 1; //容量为0时,前i个物品全不选也是一种方案
10     }
11     for (int i = 1; i <= n; i++) {
12         for (int j = 0; j <= n; j ++) {
13             dp[i][j] = dp[i - 1][j] % mod; //特殊dp[0][0] = 1
14             if (j >= i) {
15                 dp[i][j] = (dp[i - 1][j] + dp[i][j - i]) % mod;
16             }
17         }
18     }
19     cout << dp[n][n] << endl;
20     return 0;
21 }

然后再转化为一维,再从小到大循环体积

注意初值问题:
求最大值时,当都不选时,价值显然是 0
而求方案数时,当都不选时,方案数是 1(即前 i 个物品都不选的情况也是一种方案),所以需要初始化为 1
即需要这样:

for  (int i = 0; i <= n; i++)  {

  dp[i][0] = 1;

}
等价变形后: f[0] = 1

一维做法

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int N = 1010, mod = 1e9 + 7;
 4 int dp[N];
 5 int main() {
 6     int n;
 7     cin >> n;
 8     dp[0] = 1; //一个数都不选,是一种方案
 9     for (int i = 1; i <= n; i++) {
10         for (int j = i; j <= n; j++) {
11             dp[j] = (dp[j] + dp[j - i]) % mod;
12         }
13     }
14     cout << dp[n] << endl;
15     return 0;
16 }

 解法二:

 PS : 最小值1 表示 :j个数的总和是i的数中最小的数为1

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int N = 1010, mod = 1e9 + 7;
 4 int dp[N][N];
 5 int main() {
 6     int n;
 7     cin >> n;
 8     dp[0][0] = 1; //总和是0,用0个数来表示,是1种方案
 9     for (int i = 1; i <= n; i++) {
10         for (int j = 1; j <= i; j++) { //总和是i的话,最多表示成i个数的和
11             dp[i][j] = (dp[i - 1][j - 1] + dp[i - j][j]) % mod;  
12         }
13     }
14     int res = 0;
15     for (int i = 1; i <= n; i++) {
16         res = (res + dp[n][i]) % mod;
17     }
18     cout << res << endl;
19     return 0;
20 }
原文地址:https://www.cnblogs.com/fx1998/p/13235646.html