Codevs1155 金明的预算方案 ——2006年NOIP全国联赛提高组 变种经典背包dp

22 篇文章 0 订阅
20 篇文章 0 订阅

Codevs1155 金明的预算方案 ——2006年NOIP全国联赛提高组

由于至多有2个附件,直接手动枚举就好了。
dp时:

  • 如果当前物品是附件, 跳过
  • 如果当前物品时主件
    • 只选这个主件,不选它的附件
    • 当这个主件有附件时, 选它和它的第一个主件
    • 当这个主件有2个附件时, 选它和它的第二个主件
    • 当这个主件有2个附件时, 选它和它的所有附件
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <vector>
using namespace std;

#define MAXN (60+6)
#define MAXV (32000+32)
struct item{
    int v, p, q;
}l[MAXN];

int dp[MAXV];
vector <int> q[MAXN];

int main()
{
    int V, n;
    cin >> V >> n;

    for(int i = 1; i <= n; i ++)
    {
        scanf("%d%d%d", &l[i].v, &l[i].p, &l[i].q);
        if(l[i].q) q[l[i].q].push_back(i);
    }

    for(int i = 1; i <= n; i ++)
    {
        if(l[i].q) continue;
        for(int j = V; j >= 0; j --)
        {
            // 只选主件
            if(j >= l[i].v)
                dp[j] = max(dp[j], dp[j - l[i].v] + l[i].v*l[i].p);
            //只选第一件 
            if(q[i].size() && j >= l[i].v + l[q[i][0]].v)
                dp[j] = max(dp[j], dp[j - (l[i].v + l[q[i][0]].v)] + l[i].v*l[i].p + l[q[i][0]].v*l[q[i][0]].p);
            //只选第二件
            if(q[i].size() > 1 && j >= l[i].v + l[q[i][1]].v)
                dp[j] = max(dp[j], dp[j - (l[i].v + l[q[i][1]].v)] + l[i].v*l[i].p + l[q[i][1]].v*l[q[i][1]].p);
            //全选
            if(q[i].size() > 1 && j >= l[i].v + l[q[i][0]].v + l[q[i][1]].v)
                dp[j] = max(dp[j], dp[j - (l[i].v + l[q[i][0]].v + l[q[i][1]].v)] + l[i].v*l[i].p + l[q[i][0]].v*l[q[i][0]].p + l[q[i][1]].v*l[q[i][1]].p);
        }
    }

    cout << dp[V];
    return 0;
} 

另:(精简不了多少……)

#include <cstdio>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <vector>
using namespace std;

#define MAXN (60+6)
#define MAXV (32000+32)
int dp[MAXV];
struct item{
    int v, p, q;
}l[MAXN];

vector <int> q[MAXN];

int main()
{
    int V, n;
    cin >> V >> n;
    for(int i = 1; i <= n; i ++)
    {
        scanf("%d%d%d", &l[i].v, &l[i].p, &l[i].q);
        if(l[i].q) q[l[i].q].push_back(i);
    }

    for(int i = 1; i <= n; i ++)
    {
        if(l[i].q) continue; //如果是附件
        for(int j = V; j >= 0; j --)
        {
            int lson, rson;
            if(q[i].size()) lson = q[i][0];// 假设附件为 儿子 
            if(q[i].size() > 1) rson = q[i][1];

            //只选主件
            if(j >= l[i].v)
                dp[j] = max(dp[j], dp[j-l[i].v] + l[i].v*l[i].p);
            //选主件和第一个附件
            if(q[i].size() > 0 && j >= l[i].v + l[lson].v)
                dp[j] = max(dp[j], dp[j - (l[i].v + l[lson].v)] + l[i].v*l[i].p + l[lson].v*l[lson].p);
            //选主件和第二个附件
            if(q[i].size() > 1 && j >= l[i].v + l[rson].v)
                dp[j] = max(dp[j], dp[j - (l[i].v + l[rson].v)] + l[i].v*l[i].p + l[rson].v*l[rson].p);
            //全选
            if(q[i].size() > 1 && j >= l[i].v + l[lson].v + l[rson].v)
                dp[j] = max(dp[j], dp[j - (l[i].v + l[lson].v + l[rson].v)] + l[i].v*l[i].p + l[lson].v*l[lson].p + l[rson].v*l[rson].p);
        } 
    }

    cout << dp[V];
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值