01背包,完全背包求方案数与具体方案
对于背包问题求方案数与具体方案,我想分为两种题型:
- 恰好型问题——
个数,每个 满足一定范围(为定值,或取值范围是一个区间等),且 的 个数,以及求其中一组解。 - 经典背包问题——
个物品,第 个物品价值为 ,体积为 ,背包体积为 ,求获得最大价值的方案数,以及一组方案。
恰好型问题#
求方案数:设
一维形式:
只看是否可行:
对于01背包与完全背包,上述转移形式是完全相同的,唯一不同的在于体积的正倒序枚举。
求出其中一个具体方案:求具体方案的核心在于确认好某个状态是由前面哪个状态转移而来的。可以利用 是否可行 这个递推式来做——需要将上式改为另一种繁琐的形式,以确认是否真的转移过来:
if(dp[j - a[i]] == 1 && dp[j] == 0){
dp[j] = 1;
path[j] = {j - a[i], i};
}
改写为上述形式时,就可以确认
这样就可以通过第 3 行的写法(
除这个转移式外,应该也能用其他的转移式来做,以后想到了再补充。
some problems#
经典背包问题#
与上述问题不同,背包形式不仅将等式改为了不等式(
求解方案数是类似的,定义
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1010;
const int mod = 1e9 + 7;
int n, V;
int v[maxn], w[maxn];
int dp[maxn][maxn];
int cnt[maxn][maxn];// cnt[i][j] 对应 dp[i][j]状态下的方案数
int main()
{
cin >> n >> V;
for(int i = 1; i <= n; i++){
cin >> v[i] >> w[i];
}
for (int i = 0; i <= V; i++)//从前0个物品中选,相当于任何体积下都只有不选一种方案(此时取价值的情况只有0,也是最大价值),cnt==1
{
cnt[0][i] = 1;
}
for (int i = 1; i <= n; i++){
for (int j = 0; j <= V; j++){
if (j < v[i] || dp[i - 1][j] > dp[i - 1][j - v[i]] + w[i]){ // 1
cnt[i][j] = cnt[i - 1][j];
}
else if (dp[i - 1][j] < dp[i - 1][j - v[i]] + w[i]){ // 2
cnt[i][j] = cnt[i - 1][j - v[i]];
}
else if (dp[i - 1][j] == dp[i - 1][j - v[i]] + w[i]){ // 3
cnt[i][j] = (cnt[i - 1][j] + cnt[i - 1][j - v[i]]) % mod;
}
dp[i][j] = dp[i - 1][j];
if(j >= v[i]) dp[i][j] = max(dp[i][j], dp[i - 1][j - v[i]] + w[i]);
}
}
cout << cnt[n][V] << endl;
return 0;
}
可以看出上面的三个转移的特点——
一维形式:
if(dp[j] < dp[j - v[i]] + w[i]){
cnt[j] = cnt[j - v[i]]
}
else if(dp[j] == dp[j - v[i]] + w[i]){
cnt[j] += cnt[j - v[i]];
}
//else{ // 可省略
//}
01背包与完全背包区别也仅在于体积的正倒序枚举。
求解具体方案和上面也是类似的——看
若规定选择物品总体积恰好为
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战