计数类DP
整数划分
【题目链接】900. 整数划分 - AcWing题库
样例剖析:
5的7种划分如下:
5
4 1
3 2
3 1 1
2 2 1
2 1 1 1
1 1 1 1 1
思路:
把1,2,3, … n分别看做n个物体的体积,这n个物体均无使用次数限制,问恰好能装满总体积为n的背包的总方案数(完全背包问题变形)
f[i][j]
表示前i个整数(1,2…,i)恰好拼成j的方案数
f[i][j] = f[i - 1][j] + f[i - 1][j - i] + f[i - 1][j - 2*i] + f[i - 1][j - 3*i].....
f[i][j - i] = f[i - 1][j - i] + f[i - 1][j - 2*i] + f[i - 1][j - 3*i] .....
因此:
f[i][j] = f[i - 1][j] + f[i][j - i]
(类似完全背包的推导!)即一维:
f[j] = f[j] + f[j - i]
初值问题:当一个数都不选的时候,只有一种方案
即:for (int i = 0; i <= n; i ++)
f[i][0]
= 1;
等价变形后: f[0] = 1
【代码实现】
二维:
#include <iostream>
using namespace std;
const int N = 1e3 + 7, mod = 1e9 + 7;
int f[N][N];
int main()
{
int n;
cin >> n;
for (int i = 0; i <= n; i ++)
{
f[i][0] = 1; // 容量为0时,前 i 个物品全不选也是一种方案
}
for (int i = 1; i <= n; i ++)
{
for (int j = 0; j <= n; j ++)
{
f[i][j] = f[i - 1][j] % mod;
if (j >= i) f[i][j] = (f[i - 1][j] + f[i][j - i]) % mod;
}
}
cout << f[n][n] << endl;
}
一维:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1010, mod = 1e9 + 7;
int dp[N];
int main()
{
int n;
cin >> n;
dp[0] = 1;// 容量为0时,前 i 个物品全不选也是一种方案
for(int i = 1; i <= n; i ++)
for(int j = i; j <= n; j ++)
dp[j] = (dp[j] + dp[j - i]) % mod;
cout << dp[n];
return 0;
}
学习参考:
acwing算法基础课