#include using namespace std; // 利用二进制枚举进行分组 const int N = 60, M = 32010; struct Node { int v, w; }; int n, m; vector a[N]; // 主件 vector b[N]; // 附件 int f[M]; int main() { cin >> m >> n; // 总钱数,希望购买物品的个数 for (int i = 1; i <= n; i++) { int v, p, q; cin >> v >> p >> q; // 价格,重要度,主件还是附件 if (!q) a[i].push_back({v, p * v}); // q==0,主件,第i个物品是主未入库,体积是v,价格是p*v else b[q].push_back({v, p * v}); // q>0,附件,它的主件是q,需要维护主件附件的关系,b[q].add(附件) } // 利用二进制枚举,生成分组的所有组合情况 for (int i = 1; i <= n; i++) { if (!a[i].size()) continue; // 只讨论主件,由主件进行构建 for (int j = 0; j < 1 << b[i].size(); j++) { // 主件i的所有附件组合情况,比如 000,001,010,...,111 int v = a[i][0].v, w = a[i][0].w; // 主件体积和主件价值 for (int k = 0; k < b[i].size(); k++) // 主件i的所有附件 if (j >> k & 1) v += b[i][k].v, w += b[i][k].w; // 此数字描述多少个数位是1 // 组合的一种情况 a[i].push_back({v, w}); } } // 分组背包模板 for (int i = 1; i <= n; i++) for (int j = m; j >= 0; j--) for (int k = 0; k < a[i].size(); k++) // 注意:这里k是从0开始,因为vector的特点决定 if (j >= a[i][k].v) f[j] = max(f[j], f[j - a[i][k].v] + a[i][k].w); // 输出 printf("%d\n", f[m]); return 0; }