#include<iostream>
#include<cstdio>
#include<cstdlib>
//#include<bits/stdc++.h>
using namespace std;
struct A{
    int v;
    int p;
    int q;
}a[65],d[65][65];
int n,m,t[65],dp[32000],V[65][10],P[65][10],cnt[65],ans;
int main(){
    cin>>n>>m;
    for(int i=1;i<=m;i++){
        cin>>a[i].v>>a[i].p>>a[i].q;
        if(a[i].q){//如果这个物品是一个附件,a[i].q是该附件所依附的主件
            t[a[i].q]++;//附件存储处理t[i]表明第i个主件有几个附件
            d[a[i].q][t[a[i].q]].v=a[i].v;
            d[a[i].q][t[a[i].q]].p=a[i].p;
            d[a[i].q][t[a[i].q]].q=a[i].q;
        }
    }
    for(int i=1;i<=m;i++){//循环每一个物品,第i个物品
        if(t[i]){//如果有附件
            memset(dp,-1,sizeof(dp));
            for(int j=1;j<=t[i];j++){//01背包处理 遍历该主件的附件
                for(int o=n-a[i].v;o >= d[i][j].v;o--){//d[i][j]表示第i个物品的第j个附件,o表示剩下的钱,减去a[i]表示买了这个主件
                    if(dp[o]<dp[o-d[i][j].v]+d[i][j].v*d[i][j].p && dp[o-d[i][j].v] != -1){//价值为期望度*价格,恰好装满
                        dp[o]=dp[o-d[i][j].v]+d[i][j].v*d[i][j].p;//如果恰好装满则赋值
                    }
                }
            }
            for(int j=0;j<=n-a[i].v;j++){
                if(dp[j]!=-1){//如果恰好装满
                    cnt[i]++;
                    V[i][cnt[i]]=j+a[i].v;
                    P[i][cnt[i]]=dp[j]+a[i].v*a[i].p;//把此情况存在主件i的分组中,为分组背包做好处理
                }
            }
        }
        if(!a[i].q){//单纯购买主件
            cnt[i]++;
            V[i][cnt[i]]=a[i].v;
            P[i][cnt[i]]=a[i].v*a[i].p;//存储
        }
    }
    memset(dp,0,sizeof(dp));
    for(int i=1;i<=m;i++) {//所有的主件数m多重背包喵喵喵?????
        for (int j = n; j >= 0; j--) {//遍历所有的钱
            for (int k = 1; k <= cnt[i]; k++) {//遍历所有的分组
                if (j >= V[i][k]) {//01动态规划
                    dp[j] = max(dp[j], dp[j - V[i][k]] + P[i][k]);
                }
            }
        }
    }
    for(int i=0;i<=n;i++)
        ans=max(ans,dp[i]);
    printf("%d",ans);
    return 0;
}

按照题解自己重新打了一边代码
似乎有那么一点感觉了。