// 购物单 #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; }
使用分组背包的思想:按照主件分组,将单独主件,主件+一件附件,主件+两件附件作为一个物品组,物品组中可能有四个物品,物品互斥,只能选其中一种或者不选,然后计算分组背包,思路看的背包九讲,然后试着实现一下,菜鸡轻喷