背包问题思路
假设有i种物品 c【i】克 v【i】元,有客人只看重量,需要买性价比高的物品装进背包。
用i表示选第几个物品,j表示背包的容量 ,f【i】【j】;
怎么知道性价比?:1.选第i个物品 2.不选第i个物品
1.的表示方法: f[i-1][j-c[i]]+v[i] //j-c[i]是容量减去第i个物品的重量,剩余空间需要用[i-1]来装。
// 于是选择第i个物品重量v[i]加上剩余重量f[i-1][j-c[i]]就是1.的表示方法
2.的表示方法: f[i-1][j]
选择性价比方法写为: f[i][j]=max(1.的表示方法,2.的表示方法)
但是,dp是用两个一维数组解题,所以得把二维数组的方法转换为一维数组
又但是,由于一维数组会非常恐怖的覆盖之前的结果,不得不用两个数组来维护,巧妙的是dp用从后往前更新数据
01背包模板
1.求价值最大化
int n,m,c[Maxn],v[Maxn],dp[Maxn]//c[i]重量,v[i]价值
for(int i=1;i<=n;i++){
for(int j=m;j>=c[i];j--{
dp[j]=max(dp[j],dp[j-c[i]]+v[i]);
}
}
2.求方案总数
int n,m,c[Maxn],v[Maxn],dp[Maxn]//c[i]重量,v[i]价值
dp[0]=1;
for(int i=1;i<=n;i++){
for(int j=m;j>=c[i];j--{
dp[j]=dp[j]+dp[j-c[i]];//c[i]根据实际情况变化
}
}
完全背包模板
int n,m,c[Maxn],v[Maxn],dp[Maxn]//c[i]重量,v[i]价值
for(int i=1;i<=n;i++){
for(int j=c[i];j>=m;j--{
dp[j]=max(dp[j],dp[j-c[i]]+v[i]);
}
}
分组背包模板
int m,n,c[1010],v[1010],b[1010],dp[1010],g[205][205],s,num;
int main()
{
cin>>m>>n;
for(int i=1;i<=n;i++){
cin>>c[i]>>v[i]>>s;
num=max(s,num);//有几个组?这是个未知的问题,s有多大就有几个组
b[s]++;//分组背包用于看每组有几个物品?
g[s][b[s]]=i;//第几组中第几个物品的编号,为什么要求编号?因为后面要比较选出每个组价值最高的物品
}
for(int i=1;i<=num;i++){//分组背包模板
for(int j=m;j>=0;j--){
for(int k=1;k<=b[i];k++){//枚举小组中所有成员
if(j>=c[g[i][k]]){
dp[j]=max(dp[j],dp[j-c[g[i][k]]]+v[g[i][k]]);
}
}
}
}
cout<<dp[m];
return 0;
}