此处给出计数 dp 与背包问题结合的两道题。
整数划分
本题可转化为完全背包问题,背包容量为 n ,物品的体积为 n, n-1, ... ,1 ,要求出装满背包的方案数。
下面列出思路:
利用滚动数组优化,得出以下代码:
#include <iostream>
#include <cstdio>
using namespace std;
const int N=1005,I=1e9+7;
int n,f[N];
int main()
{
f[0]=1; // 计数类 dp 务必初始化
cin>>n;
for(int i=n;i>=1;i--) // 遍历各个“物品”
for(int j=i;j<=n;j++)
f[j]=(f[j]+f[j-i])%I; // % 和 / 优先级相同
cout<<f[n];
return 0;
}
最优方案数
要知最大价值(方便找最优选法),用 f[i][j] 表示在前 i 个物品中选择,总体积不超过 j 时的最大价值,设 g[i][j] 表示此时的选法数量
更新时,( v, w 分别为物品 i 的体积、价值)。如果左侧数值大,;若右侧大,;若左右相等,则
滚动数组优化后可得:
#include <iostream>
#include <cstdio>
using namespace std;
const int N=1005,mod=1e9+7;
int f[N],g[N];
int n,m;
int main()
{
cin>>n>>m;
// 与上题不同
// 本题设的是“不超过”,故最开始在任意体积下,都有什么也不选的一种方案
for(int i=0;i<=m;i++) g[i]=1;
while(n--)
{
int v,w;
cin>>v>>w;
for(int j=m;j>=v;j--)
{
if(f[j]<f[j-v]+w)
{
f[j]=f[j-v]+w;
g[j]=g[j-v];
}
else if(f[j]==f[j-v]+w)
g[j]=(g[j]+g[j-v])%mod;
}
}
cout<<g[m];
return 0;
}