动态规划【4】之混合背包

10 篇文章 0 订阅
9 篇文章 0 订阅

混合背包就是将前面三种的背包问题混合起来,有的只能取一次,有的能取无限次,有的只能取 k k k次。1

例题:luogu1833 樱花

事实上,我们直接对不同的物品按情况讨论即可。
关于混合背包,0/1背包可以看成是多重背包的特例( k = 1 k=1 k=1),因此,仅考虑两种情况即可。

luogu1833 樱花对应的代码如下:

/* ***********************************************
Author        : VFVrPQ
Created Time  : 五  2/28 15:39:08 2020
File Name     : luogu1833樱花.cpp
Problem       : 
Description   : 
Solution      : 
Tag           : 
************************************************ */

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <cmath>
#include <cstdlib>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <iomanip>
using namespace std;
#define DEBUG(x) cout<<x<<endl;
const int N = 1e4+10;
const int M = 1e9+7;
const int INF = 1e9+7;

string ts, te;
int n;
int t[N],c[N],p[N];
int dp[N];

int getStr(string t){
    int i;
    int ret = 0;
    for (i=0;t[i]!='\0';i++){
        if (t[i]==':') break;
        ret = ret * 10 + t[i]-'0';
    }
    ret*=60; //转换成分钟
    int now = 0;
    for (i+=1;t[i]!='\0';i++){
        now = now * 10 + t[i]-'0';
    }
    return ret+now;
}
int main()
{
    cin >> ts >> te >> n;
    for (int i=1;i<=n;i++){
        cin >> t[i] >> c[i] >> p[i];
    }
    int maxT = getStr(te) - getStr(ts);
    
    for (int i=1;i<=n;i++){
        if (p[i] == 0){//完全背包
            for (int j=t[i];j<=maxT;j++) dp[j] = max(dp[j], dp[j-t[i]]+c[i]);
        }else {//多重背包
            for (int k=1;;k*=2){
                int now = k;//当前的物品个数
                if (now >= p[i]) now = p[i];//取较小者

                for (int j=maxT;j>=now*t[i];j--) dp[j] = max(dp[j], dp[j-now*t[i]]+now*c[i]);//now*的0/1背包
                p[i] -= now;
                if (p[i]==0) break;
            }
        }
    }
    printf("%d\n",dp[maxT]);
    //for (int i=0;i<=maxT;i++) printf("%d ",dp[i]);
    //printf("%d\n",maxT);
    return 0;
}

  1. https://oi-wiki.org/dp/knapsack/#_5 ↩︎

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值