背包衍化——二维01背包

问题引入

有两种物品捆绑销售,每种包装里两种物品各有 x , y x,y x,y个,售价为 t t t元,共有 s s s个捆绑销售的包装。现在需要两种物品 n , m n,m n,m个,问如何购买可以满足需要并且花费最少的钱

状态转移

d [ i ] [ j ] d[i][j] d[i][j]表示第一、二种物品分别买了 i , j i,j i,j个的最小花费,那么状态转移方程为:

d [ i ] [ j ] = m i n ( d [ i ] [ j ] , d [ i − x ] [ j − y ] + t ) d[i][j]=min(d[i][j],d[i-x][j-y]+t) d[i][j]=min(d[i][j],d[ix][jy]+t)

边界处理

但是这里需要注意的是,不难发现 i − x , j − y i-x,j-y ix,jy需要大于等于 0 0 0,按照习惯应该写:

for (int i = 0, x, y, t; i < s; i++) {
    cin >> x >> y >> t;
    for (int j = n; j >= x; j--)
        for (int k = m; k >= y; k--)
            d[j][k] = min(d[j][k], d[j - x][k - y] + t);
}

但是这样是错误的,原因是如果这样写就变成了恰好拿 n , m n,m n,m个物品,而本题对上界没有要求,那么也就是说当背包容量溢出后,在状态转移时实际上变成了负值,那么我们都从 d [ 0 ] [ 0 ] d[0][0] d[0][0]这个状态转移即可:

for (int i = 0, x, y, t; i < s; i++) {
    cin >> x >> y >> t;
    for (int j = n; j >= 0; j--)
        for (int k = m; k >= 0; k--)
            d[j][k] = min(d[j][k], d[max(j - x, 0)][max(k - y, 0)] + t);
}
初始化

d [ 0 ] [ 0 ] = 0 d[0][0]=0 d[0][0]=0,其余均为 i n f inf inf

代码
int s, n, m;
cin >> s >> n >> m;
memset(d, 0x3f, sizeof d);
d[0][0] = 0;
for (int i = 0, x, y, t; i < s; i++) {
    cin >> x >> y >> t;
    for (int j = n; j >= 0; j--)
        for (int k = m; k >= 0; k--)
            d[j][k] = min(d[j][k], d[max(j - x, 0)][max(k - y, 0)] + t);
}
cout << d[n][m] << ENDL;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值