一个抽象的分组背包问题,然后最后的解是要遍历所有DP数组,而不是只有最后一个,因为背包在遍历的过程中扩大了!!!具体为什么我也不清楚。
将M种装饰珠看做M个组,里面值只能选一个,装饰孔看做背包容量。如何正确的选择M个组里面每一个值的选取范围是一个关键问题。按照统计的装饰孔的等级倒着来(从大到小),是一个巧妙的方法。
#include<iostream>
#include<vector>
#include<algorithm>
#include<cstring>
using namespace std;
bool cmp(pair<int,vector<int>> a,pair<int,vector<int>> b)
{
return a.first>b.first;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
vector<int> h(5,0);
int tol=0;
for(int i=0;i<6;i++)
{
int N;cin>>N;
for(int j=0;j<N;j++)
{
int l;cin>>l;
h[l]++;
}
tol+=N;
}
int M;cin>>M;
vector<pair<int,vector<int>>> a(M+1);
for(int i=1;i<=M;i++)
{
cin>>a[i].first;
int P;cin>>P;
a[i].second.resize(P+1);
for(int j=1;j<=P;j++)
cin>>a[i].second[j];
}
//sort(a.begin(),a.end(),cmp);
vector<vector<int> > dp(M+1,vector<int>(tol+1,0)); //不要求恰好装满,所以0为初始值
int vol=0;
int kind=0;
for(int i=4;i>=1;i--)//孔数
{
vol+=h[i];//动态增加背包容量,限制在正确的范围之内
for(int k=1;k<=M;k++)//浏览组别
{
if(a[k].first==i)
{
kind++;//表示第几组
for (int v = 1; v <= vol; ++v)//第Kind组一件也不选
{
dp[kind][v] = dp[kind - 1][v];
}
for(int v=1;v<=vol;v++)//遍历背包容量
for(int j=1;j<a[k].second.size();j++)//第kind组里面只选一件,相互对比
{
if(v<j)
continue;
else
dp[kind][v]=max(dp[kind][v],dp[kind-1][v-j]+a[k].second[j]);
}
}
}
}
//cout<<dp[kind][vol]<<endl;// 背包扩大,最优解不一定是这个
cout<<*max_element(dp[kind].begin(),dp[kind].end())<<'\n';
return 0;
}