// 购物单
#include <bits/stdc++.h>
using namespace std;
const int N = 65;
int n, m; // n表示预算,m表示物品的数量
struct MainGoods
{
int vi; // 主件价格
int pi; // 主件重要性
int num; // 附件数量
int v[2], p[2]; // v表示价格,p表示重要性
} mg[N];
int gv[N][N], gsa[N][N], gs[N]; // gv表示某组的某物品价格,gsa表示某组的某物品满意度,gs表示组中物品数量
int f[32000];
int main()
{
cin >> n >> m;
for (int i = 1; i <= m; i++) // 编号从1开始,主件编号同样使用i
{
int a, b, c; // a表示价格,b表示重要性,c==0表示主件,c>0表示附件编号
cin >> a >> b >> c;
// 主件有0,1,2个附件,按照主件分组,每组有四个物品
if (c > 0)
{
mg[c].v[mg[c].num] = a;
mg[c].p[mg[c].num] = b;
mg[c].num++;
}
else
{
mg[i].vi = a;
mg[i].pi = b;
}
}
// 遍历所有主件生成四种物品
int cnt = 0; // 组数
for (int i = 1; i <= m; i++)
{
if (mg[i].vi == 0)
continue;
cnt++;
if (mg[i].num == 0)
{
gs[cnt] = 1;
gv[cnt][0] = mg[i].vi;
gsa[cnt][0] = mg[i].vi * mg[i].pi;
}
else if (mg[i].num == 1)
{
gv[cnt][0] = mg[i].vi;
gsa[cnt][0] = mg[i].vi * mg[i].pi;
gv[cnt][1] = mg[i].vi + mg[i].v[0];
gsa[cnt][1] = mg[i].vi * mg[i].pi + mg[i].v[0] * mg[i].p[0];
gs[cnt] = 2;
}
else if (mg[i].num == 2)
{
gv[cnt][0] = mg[i].vi;
gsa[cnt][0] = mg[i].vi * mg[i].pi;
gv[cnt][1] = mg[i].vi + mg[i].v[0];
gsa[cnt][1] = mg[i].vi * mg[i].pi + mg[i].v[0] * mg[i].p[0];
gv[cnt][2] = mg[i].vi + mg[i].v[1];
gsa[cnt][2] = mg[i].vi * mg[i].pi + mg[i].v[1] * mg[i].p[1];
gv[cnt][3] = mg[i].vi + mg[i].v[0] + mg[i].v[1];
gsa[cnt][3] = mg[i].vi * mg[i].pi + mg[i].v[0] * mg[i].p[0] + mg[i].v[1] * mg[i].p[1];
gs[cnt] = 4;
}
}
// 求不超过n,所能获得的最大满意度
for (int i = 1; i <= cnt; i++)
{
for (int j = n; j >= 0; j--)
{
// 分组背包
for (int k = 0; k < gs[i]; k++)
{
if (j >= gv[i][k])
f[j] = max(f[j], f[j - gv[i][k]] + gsa[i][k]);
}
}
}
cout << f[n];
return 0;
}
使用分组背包的思想:按照主件分组,将单独主件,主件+一件附件,主件+两件附件作为一个物品组,物品组中可能有四个物品,物品互斥,只能选其中一种或者不选,然后计算分组背包,思路看的背包九讲,然后试着实现一下,菜鸡轻喷

京公网安备 11010502036488号