1、普通01背包
for i=1:n
for j=0:W
if(j<w[i])
dp[i][j]=dp[i-1][j];
else
dp[i][j]=max(dp[i][j],dp[i][j-w[i]]+w[i];
2、01背包问题之2
题目特征:背包重量太大,开不了那么大的数组。普通01背包中的时间复杂度O(nW),现在就不够用了。
解决方案:价值的范围较小,试着改变dp的方向。之前的方法中,针对不同的重量限制计算最大的价值,现在针对不同的价值计算最小的重量。
状态定义:dp[i][j] 前i个物品中挑选出价值总和为j时总重量的最小值(不存在时是一个充分大的INF),初始值dp[0][0]=0,dp[0][j]=INF。
状态转移:
最终答案:的最大(时间复杂度)
hdu 6495冰水挑战
思路:背包载荷是c,每个物品的重量是ai,每个物品的价值是1。一般来说,会想到针对不同的体力计算最大的挑战个数,也就是dp[i][j]代表考虑j点体力最多能挑战多少个,这样的话j的数据量到达1e9,时空复杂度都hold不住,相对的针对挑战个数考虑体力的最小值的话(针对价值考虑重量),挑战个数的最大值是n,1e3,时间复杂度就是1e3*1e3
针对挑战个数考虑体力的最小值的话----->为了方便处理本题,改成求剩余体力的最大值,dp[n][i]>0的最大的i就是答案
注意不管咋样,他都是个01背包,按照不选和选两种情况分类讨论即可
不选它:参考普通01背包,dp[i][j]=dp[i-1][j], dp[i][j]=dp[i-1][j]+c[i] 本题额外判断它是否能从dp[i-1][j]转移过来,即dp[i-1][j]>0
选它:参考01背包,dp[i][j=max(dp[i][j],dp[i][j-w[i]]+v[i]), dp[i][j]=max(dp[i][j],挑战它之前的体力-a[i]+c[i]),注意由于选它dp[i][j]一定是由dp[i-1][j-1]转移过来的,所以挑战它之前的体力=min(dp[i-1][j-1],b[i]),要判断是否能成功转移
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long LL;
const int N=1e3+10;
LL a[N],b[N],c[N];
LL dp[N][N]; //最多能完成n个挑战 总价值最大是n4
//减少的体力最小-->剩下的体力最大
//写二维的时候感觉还是正着写比较酥服
int n;
LL C;
const int INF=1e9;
int main()
{
int T;
cin>>T;
while(T--)
{
cin>>n>>C;
for(int i=1;i<=n;++i)
cin>>a[i]>>b[i]>>c[i];
memset(dp,-INF,sizeof(dp));
dp[0][0]=C;
for(int i=1;i<=n;++i) //要得到体力消耗的最小值
{
for(int j=0;j<=n;++j)
{
if(dp[i-1][j]>0)
dp[i][j]=max(dp[i][j],dp[i-1][j]+c[i]);
if(j)
{
int tmp=min(dp[i-1][j-1],b[i]);
if(tmp>a[i]) //考虑选它
{
dp[i][j]=max(dp[i][j],tmp-a[i]+c[i]); //c[i]写外面了可真是该死
}
}
}
}
int ans;
for(int i=n;i>=0;--i)
{
if(dp[n][i]>0)
{
ans=i;
break;
}
}
cout<<ans<<endl;
}
}
3、超大背包问题
nyoj 1091
https://blog.csdn.net/zhou_yujia/article/details/52596058
https://blog.csdn.net/M_GSir/article/details/52564564
https://blog.csdn.net/mengxiang000000/article/details/53114701 折半枚举 codeforces
https://blog.csdn.net/qq_24489717/article/details/49950027 DFS和折半枚举两种方案