【luogu P1064】 金明的预算方案
https://www.luogu.org/problemnew/show/P1064
从题目描述中可以很清楚地看出这是一个背包问题, 并且只有两类物品:主件和附件。所以这是一个非树形有依赖的背包问题。先对每种主件的 附件的集合 进行一次 01背包处理,就可以先求出 对于每一种主件包括其附件的组合中,每种花费的最大价值。
这样可以得到主件k的附件中费用依次为0∼n−v[k]时的相应最大价值f[0∼n−v[k]],那么我们就得到了主件k及其附件集合的n−v[k]+1种不同选择情况,其中费用为v[k]+t的物品的价值就是f[t]+v[k]∗p[k]。
代码:
#include<cstdio> #include<algorithm> #include<iostream> #include<cmath> #include<cstring> using namespace std; struct node { int v, p, q; } a[65], p[65][65]; int n, m; int t[65], V[65][15], F[65][15], cnt[65], f[32005], ans; int main() { scanf("%d %d", &n, &m); for(int i = 1; i <= m; i++) { scanf("%d %d %d", &a[i].v, &a[i].p, &a[i].q); if(a[i].p) { t[a[i].q]++; p[a[i].q][t[a[i].q]].v = a[i].v; p[a[i].q][t[a[i].q]].p = a[i].p; p[a[i].q][t[a[i].q]].q = a[i].q; } } for(int i = 1; i <= m; i++) { if(t[i]) { memset(f,-1,sizeof(f)); f[0] = 0; for(int j = 1; j <= t[i]; j++) for(int k = n - a[i].v; k >= p[i][j].v; k--) if(f[k] < f[k - p[i][j].v] + p[i][j].v * p[i][j].p && f[k - p[i][j].v] != -1) f[k] = f[k - p[i][j].v] + p[i][j].v * p[i][j].p; for(int j = 0; j <= n - a[i].v; j++) if(f[j] != -1) { cnt[i]++; V[i][cnt[i]] = j + a[i].v; F[i][cnt[i]] = f[j] + a[i].v * a[i].p; } } if(!a[i].q) { cnt[i]++; V[i][cnt[i]] = a[i].v; F[i][cnt[i]] = a[i].v * a[i].p; } } memset(f,0,sizeof(f)); for(int i = 1; i <= m; i++) for(int j = n; j >= 0; j--) for(int k = 1; k <= cnt[i]; k++) if(j >= V[i][k]) f[j] = max(f[j],f[j - V[i][k]] + F[i][k]); for(int i = 0; i <= n; i++) ans = max(ans,f[i]); printf("%d",ans); return 0; }