金明的预算方案【动态规划】

有依赖的01背包问题

dp做的时候要层次清晰,先设计好的状态,再考虑转移,转移考虑的是有什么决策,而考虑决策必须谨慎,不能遗漏。最后考虑边界,如果说实在处理不了边界就可以把第一个阶段的答案先跑出来,对于状态的设计,可以想一下答案是怎么设计的

方便起见,我们把状态只定义在主件上(对输入进行特殊处理)
每个主件有0,1,2个附件
每次购买时,有五种选择
1.不买
2.只买主件
3.买主件和一号附件
4.买主件和二号附件
5.买主件和全部附件

[i][0]表示主件的价值与花费
[i][1]表示一号附件的价值与花费
[i][2]表示二号附件的价值与花费
当一个物品没有附件时,[i][1]和[i][2]均为0

状态转移方程(只是一个思路方程,不完整!没有写乘上期望值什么的,具体方程请往下看代码)
f(i,j) = max (
f(i-1,j),//不买
f(i-1,j - c[i][0]) + v[i][0],//只买主件
f(i-1,j - c[i][0] - c[i][1]) + v[i][0] + v[i][1],//主件和一号附件
f(i-1,j - c[i][0] - c[i][2]) + v[i][0] + v[i][2],//主件和二号附件
f(i-1,j - c[i][0] - c[i][1] - c[i][2]) + v[i][0] + v[i][1] + v[i][2],//主件和全部附件
)

#include <cstdio>
#include <algorithm>
int f[72][32010],m,n,c[72][3],v[62][3];
int main() {
    scanf("%d%d",&n, &m);
    for(int i=1; i<=m; i++) {
        int w, p, q;
        scanf("%d %d %d",&w,&p,&q);
        if(q == 0) {
            c[i][0] = w;
            v[i][0] = p;
            continue;

        }
        if(!v[q][1]) { // 如果第一个附件还没有遇到 
            c[q][1] = w;
            v[q][1] = p;
        }
        else { //如果已经遇到第一个附件 
            c[q][2] = w;
            v[q][2] = p;
        }
    }
    for(int i=1; i<=m; i++) {

        for(int j=10; j<=n; j+=10){

            if(j-c[i][0]>= 0) {

                f[i][j] = std::max(f[i-1][j],f[i-1][j-c[i][0]] + v[i][0]*c[i][0]);

            if(j - c[i][0] - c[i][1] >= 0)

                f[i][j] = std::max(f[i][j],f[i-1][j-c[i][0]-c[i][1]] + v[i][1]*c[i][1] + v[i][0]*c[i][0]);  

            if(j - c[i][0] - c[i][2]>= 0)

                f[i][j] = std::max(f[i][j],f[i-1][j-c[i][0]-c[i][2]] + v[i][2]*c[i][2] + v[i][0]*c[i][0]);

            if(j-c[i][0] - c[i][1] - c[i][2] >= 0)

                f[i][j] = std::max(f[i][j],f[i-1][j-c[i][0]-c[i][1]-c[i][2]] + v[i][2]*c[i][2] + v[i][1]*c[i][1] + v[i][0]*c[i][0]);

            }
            else
                f[i][j] = f[i-1][j];
        }
    }
    printf("%d",f[m][n]);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值