【luogu P1064】 金明的预算方案

https://www.luogu.org/problemnew/show/P1064

  从题目描述中可以很清楚地看出这是一个背包问题, 并且只有两类物品:主件和附件。所以这是一个非树形有依赖的背包问题。先对每种主件的 附件的集合 进行一次 01背包处理,就可以先求出 对于每一种主件包括其附件的组合中,每种花费的最大价值。

这样可以得到主件k的附件中费用依次为0nv[k]时的相应最大价值f[0nv[k]],那么我们就得到了主件k及其附件集合的nv[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;
}
View Code

 

 

 

posted @ 2019-06-16 11:29  机器闵  阅读(131)  评论(0编辑  收藏  举报