目录
练习题:
P1064 [NOIP2006 提高组] 金明的预算方案 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
这种题直接当附件有无数多个做吧
思路:
即标题 : 主件最后放,放主件时才更新最终背包
细节:
1.有主件与附件,买附件一定要买主件。(计算价值时,是物件的价格*重要度)
2.说最终背包,说明我们还有个背包,即临时背包。
我们令最终背包为fdp,临时背包为dp。
3.我们每次处理一组,一组指的是一个主件及其所有附件。
临时背包dp就对附件做计算(即01背包的计算),然后最后对主件计算时(也是背包)才往最终背包fdp里放。
4.所以我开局分了组。
主件是第几个就放到第几个vector<vector<int>>里,他的附件都放主件一个vector<int>里
每次处理一个vector<int>,里面放的是主件和他的附件的编号(因为此题是这样的编号),然后倒着来(但主件也未必是他们之中第一个出现,所以最后再处理主件吧)
AC代码:
每次记得用最终背包fdp清理临时背包dp
const int MAX = 1e5;
int v[MAX], p[MAX], q[MAX];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n, m;
cin >> n >> m;
vector<vector<int>>arr(m + 1);
for (int i = 1; i <= m; i++)
{
cin >> v[i] >> p[i] >> q[i];
if (q[i] != 0)//0说明本身主件,不是0就去找自己的主件数组,就完成了分组
{
arr[q[i]].push_back(i);
}
else
{
arr[i].push_back(i);
}
}
int dp[MAX] = { 0 }, fdp[MAX] = { 0 };
for (int i = 1; i <= m; i++)
{
for (int k = arr[i].size() - 1;k>=0;k--)//附件的01背包找最大价值
{
int x = arr[i][k];
if (x != i)
for (int j = n - v[arr[i][0]]/*留位子*/; j >= v[x]; j-=1)
{
dp[j] = max(dp[j], dp[j - v[x]] + v[x]*p[x]);
}
}
if(arr[i].size()>0)
for (int j = n; j >= v[i]; j -= 1)//买到主件才算数
{
fdp[j] = max(fdp[j], dp[j - v[i]] + v[i] * p[i]);
}
memcpy(dp, fdp, sizeof fdp);
}
cout << fdp[n];
return 0;
}