dp--背包
背包问题
01背包
\(n\)个物品,每个物品都有一个价值和体积,有一个容量为\(V\)的背包,最大可以得到的价值是多少
每个物品都有两种可能,选与不选
code
for(int i = 0; i < n; i++)
{
for(int j = m; j >= w[i]; j--)
{
f[j]=max(f[j],f[j-w[i]]+v[i]);
}
}
背包恰好装满
定义\(dp[i]\)表示\(i\)状态可达,初始化\(dp\)为\(0\),代表不可达,\(dp[0] = 1\),代表可达
状态转移方程\(dp[i] = max(dp[i],dp[i-a[i]])\)
code
for(int i = 1; i <= n; i++)
{
for(int j = V; j >= a[i]; j++)
{
dp[j] = max(dp[j],dp[j-a[i]]);
}
}
完全背包
每个物品可以取任意次,而不是一次,所以我们就不用担心\(01\)背包的状态覆盖问题
直接从\(a[i]\)遍历到\(V\)
code
for(int i=1; i<=n; i++)
{
for(int j=w[i]; j<=m; j++) //和01背包的唯一区别
{
f[j]=max(f[j],f[j-w[i]]+v[i]);
}
}
多重背包转01背包
多重背包例题
每个物品可以取\(c\)次
二进制优化
我们把\(c\)次划分成\(1,2,4,8...\)之类的数,然后进行\(01\)背包就行了
一定存在某个最优的次数,而划分成二进制一定可以表示成那个数
code
for(int i = 0,a,b,c; i < n; i++)
{
scanf("%d%d%d",&a,&b,&c); //价值,重量,数量
int k = 1;
while(c-k > 0)
{
v[t] = k*a;
w[t++] = k*b;
c -= k;
k *= 2;
}
v[t] = c*a; //把剩下的当成一个物品
w[t++] = c*b;
}
//01背包
for(int i = 0; i < t; i++) //t个物品
{
for(int j = m; j >= w[i]; j--)
{
dp[j] = max(dp[j],dp[j-w[i]]+v[i]);
}
}
单调队列优化
二维背包
增加一维就好了,dp[i][j][k] //第i个,花费j,时间k
也可以空间优化,优化掉第一维度