@[一维优化在底下]
二维DP
闫氏DP分析法:
状态表示: f[i][j]
表示 从前i
种货币中选,且总价值恰好为j
的所有选法集合的方案数。
那么f[n][m]
就表示表示 从前n
种货币中选,且总价值恰好为m
的所有选法集合的方案数,即为答案。
集合划分:
按照第i
种货币可以选 0
个,1
个,2
个,3
个,,,,k
个划分集合 f[i][j]
。其中k*w[i] <= j
,也就是说在背包能装下的情况下,枚举第i
种货币可以选择几个。
状态计算:
f[i][j] = f[i-1][j]+f[i-1][j-w[i]]+f[i-1][j-2*w[i]],,,,,,+f[i-1][j-k*w[i]]
.
ac代码
#include<iostream>
#include<cstdio>
using namespace std;
const int N = 30,M = 1e4 +10;
long long f[N][M]; // 方案数很大使用long long 来存
int w[N];
int main()
{
int n,m;
cin>>n>>m;
for(int i = 1; i <= n; i++) cin>>w[i];
f[0][0] = 1; // 使用0种货币,凑0元钱,也是一种方案
for(int i = 1; i <= n; i++)
for(int j = 0; j <= m; j++)
{
for(int k = 0; k*w[i] <= j; k++)
f[i][j] += f[i-1][j-k*w[i]]; //状态计算方程
}
cout<<f[n][m]<<endl;
return 0;
}
一维DP
考虑优化
v
代表第i
件物品的体积(面值)
f[i][j] = f[i-1][j] + f[i-1][j-v]+f[i-1][j-2v]+,,,,,+f[i-1][j-kv])
f[i][j-v] = f[i-1,[j-v]+f[i-1][j-2v]+,,,,,+f[i-1][j-kv])
因此:
f[i][j] = f[i-1][j]+f[i][j-v])
图示:
去掉一维:
状态计算方程为: f[j] = f[j] + f[j-v]
ac代码
#include<iostream>
#include<cstdio>
using namespace std;
const int N = 1e4 + 10;
long long f[N];
int main()
{
int m,n;
cin>>n>>m;
f[0] = 1; //初始化 f[0][0] = 1
for(int i = 1; i <= n; i++)
{
int v;
cin>>v;
for(int j = v; j <= m; j++)
f[j] += f[j-v]; // 状态计算方程
}
cout<<f[m]<<endl;
return 0;
}
请问背包问题为什么需要初始化发f[0][0] = 1 , 不初始化i从0开始就数组越界,纯新手 ,求解
i从0开始,那循环的时候i-1不就成-1了吗,那不就越界了
oo , ok , thx
f[i][j] = f[i-1][j] + f[i-1][j-v]+f[i-1][j-2v]+,,,,,+f[i-1][j-kv])
f[i][j-v] = f[i-1,[j-v]+f[i-1][j-2v]+,,,,,+f[i-1][j-kv])
把
j
替换成j - v
的话,你这个是不是少了一项。请问背包问题在初始化的时候,在前 i 个 物品中选,且总价值恰好为 0 的方案数 为什么是0而不是1呢?(i 不等于0的时候)
跟着模拟会发现f[i][0]的状态会从f[i-1][0]状态转移过来,此时因为j
为0,f[i][0]就只从f[i-1][0]一个状态转移过来,即f[i][0]就等于f[i-1][0],所以f[i][0]转移之后都为1(因为f[0][0]为初始状态且等于1,因此其转移状态都是1)
解释的确实清晰,我也有这种迷惑
但是从前i种货币里面凑0元的方案实际不存在,哈哈哈
请问背包问题为什么需要初始化f[0][0] = 1 , 不初始化i从0开始就数组越界,纯新手 ,求解
f[0][0]初始化为1是根据f数组的定义,可以再看看up的数组定义含义,i从0开始的话,i-1就是-1就会越界,并且i从0开始(根据定义即为从前0中货币中选)没什么意义,因为根据f数组的含义来看除了f[0][0],其他f[0][j]都是0。
奥奥,太细了,感谢
有一个问题不太理解,为什么一维的情况j需要从小到大进行枚举?而在01背包问题中j需要从大到小进行枚举?
因为我们的状态计算方程不一样,更新状态时,要和我们的状态计算方程相对应。参考开心的金明 【 01背包问题 】 c++详细题解并且y总的背包问题视频讲解的很清楚,可以去看看。
要分清楚01背包和01完全背包,二维转一维的时候,如果想不清楚就模拟一下
我偷懒的方法,先打表出二维的数组,然后顺序逆序都试一试,那个打印结果与二维1的相同就是那个,嘿嘿
为啥f[i - 1][j - v]和f[i][j - v]里边的[i]和[i - 1]同时可以被优化掉
画表格看把
二维数组通过滚动数组被优化成一维,或者你可以偷懒先打表出二维的数组,然后顺序逆序都试一试,那个打印结果与二维1的相同就是那个,嘿嘿
🐂
大佬理解的很深入呀
谢谢hh!