用到至少选择一个,所以没有空间优化
分组背包问题:
常见的三种分组问题:
分成K组:
1、每组最多只能取一件物品
一维数组伪码:
for 0 to K 对每一组进行
for W to 0 对每一个代价进行判断 ///1
for all item i in group k ///2 这行个互换好像也对
dp[w]=max(dp[w],dp[w-c[i]]+v[i]; 每个重量保证的只有一件物品来取最大值
2、每组随意取(为01背包问题)******摘抄网络**既然上面的顺序是限制每组最多取一个,那调换一下顺序即可,其实就是01背包。******
一维伪码:
for 0 t0 K
for all item i in group k
for W to 0
dp[w]=max(dp[w],dp[w-c[i]]+v[i]);
3、每组至少取一个
没见过一维的伪代码
用二维:
dp[ki][j]表示当前组的一件物品不选
dp[ki-1][j-w[i]]+v[i] 表示这是在ki组选第一个
dp[ki][j-w[i]]+v[i] 表示在这个ki组中再次选一个
dp[ki][j](处理完后的值)=max(dp[ki][j],dp[ki-1][j-w[i]]+v[i],dp[ki][j-w[i]]+v[i]) max分开的时候要注意顺序 max(dp[ki][j],dp[ki-1][j-w[i]]+v[i])......
在初始化时是ki==0(没有组)这时是dp[0][j]=0 其余的是-inf ******解决一件物品都不取的问题
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <cstring>
#define X 10005
#define inf 0x3f3f3f3f
using namespace std;
int main()
{
int n,t;
int m,s;
cin>>n>>t;
int dp[105][105];
int c[105],g[105];
memset(dp,-inf,sizeof(dp));
memset(dp[0],0,sizeof(dp[0]));
for(int i=1;i<=n;++i)//k组
{
cin>>m>>s;
for(int j=0;j<m;++j)
{
scanf("%d%d",&c[j],&g[j]);
}
if(s==0)
{
// for(int j=0;j<=t;++j)
// dp[i][j]=-1000000;
for(int j=0;j<m;++j)
for(int p=t;p>=c[j];--p)
{
dp[i][p]=max(dp[i][p],dp[i][p-c[j]]+g[j]);
dp[i][p]=max(dp[i][p],dp[i-1][p-c[j]]+g[j]);
}
}
else if(s==1)
{
for(int j=0;j<=t;++j)
{
dp[i][j]=dp[i-1][j];//当前i个组继承前i-1个组
}
for(int j=0;j<m;++j)
{
for(int p=t;p>=c[j];--p)
{
dp[i][p]=max(dp[i][p],dp[i-1][p-c[j]]+g[j]);
}
}
}
else if(s==2)
{
for(int j=0;j<=t;++j)
{
dp[i][j]=dp[i-1][j];
}
for(int j=0;j<m;++j)
{
for(int p=t;p>=c[j];--p)
{
// dp[i][p]=max(dp[i][p],dp[i-1][p]);//不取
dp[i][p]=max(dp[i][p],dp[i][p-c[j]]+g[j]);//多个
//dp[i][p]=max(dp[i][p],dp[i-1][p-c[j]]+g[j]);//一个
}
}
}
}
// if(dp[n][t]<0)
// cout<<-1<<endl;
// else
cout<<max(dp[n][t],-1)<<endl;
return 0;
}