多重背包问题

多重背包问题

训练师小梁在一次机缘巧合中,发现了一个皮卡丘部落,她非常喜欢皮卡丘,但由于精灵球有限,所以她打算在这里逗留一段时间,部落中有n个皮卡丘,每个皮卡丘有不同的可爱度q[i] ,小梁要欣赏这些皮卡丘,但有的皮卡丘被看多了会抑郁,所以她要合理的分配时间和看的次数,收获最多的可爱度。
输入描述:
到达部落的时间e, s(24小时制时间){e, s}(24小时制时间)e, s(24小时制时间),皮卡丘的个数n(s≤e,n≤105)n (s < e, n <10^5)n(s≤e,n≤105)下面n行 t,q,s(0≤t,q,s≤105)t,q,s( 0 <t, q, s <10^5)t,q,s(0≤t,q,s≤105)分别代表:欣赏这只皮卡丘需要的时间(分钟),这只皮卡丘的可爱度,这只皮卡丘最多能看几次(s=0表示这只皮卡丘脾气很好,能看无限次)
输出描述:
一个整数,表示能获取的最大可爱度
示例1
输入
5:30 7:10 5
3 1 5
4 4 2
2 1 0
4 5 3
5 6 0
输出
120

题解这个问题就是典型的多重背包问题:

  1. 这个问题中就是c[i]==0即所用的的东西可以任意多或者是从c[i]*a[i]>W(总和加起来大于W)相当于可以任取多少件,这个就是完全背包问题;
  2. 多重背包本来为三重循环种类,重量,数量!!!一般都会T太高了复杂度
    for(int i=1;i<=n;i++)
    for(int j=W;j>=a[i];j–)
    for(int k=0;k<=c[i];k++){
    if(j-ka[i])>=0)
    dp[j] = max(dp[j], dp[j-k
    a[i]]+k*b[i]);
    }
    划重点了这里用了一个二进制优化的思想,就是把个数用二进制拆成01背包一样的;例:13我可以把它拆成1,2,4,6这几个数分别做01背包
    做完这题感觉自己对背包问题又有了新的认识哦!!!
#include<bits/stdc++.h>
#define mod 1e9+7
#define pi atan(1.0)*4.0
#define inf 0x3f3f3f3f
#define exp 0.0001
typedef long long  ll;
using namespace std;
ll dp[500000];
int W,a[200000],b[200000],c[200000],h1,h2,m1,m2,n;
void solve()
{
    memset(dp,0,sizeof(dp));
    for(int i=1;i<=n;i++)
    if(c[i]==0||a[i]*c[i]>=W){
        for(int j=a[i];j<=W;j++) //这里是按照完全背包做的哦
            dp[j]=max(dp[j],dp[j-a[i]]+b[i]);
    }
    else {
        int d=1;
        while(c[i]-d>0){
            for(int j=W;j>=a[i]*d;j--) //z这里是按照01背包哦
               dp[j]=max(dp[j],dp[j-a[i]*d]+b[i]*d);
         c[i]-=d;
         d*=2;
        }
        if(c[i]){ //偶数的时候会有剩余按照从1,2,4...这个分法
            for(int j=W;j>=a[i]*c[i];j--)
               dp[j]=max(dp[j],dp[j-a[i]*c[i]]+b[i]*c[i]);
        }
    }
    printf("%lld\n",dp[W]);
}
int main()
{
    while(~scanf("%d:%d %d:%d %d",&h1,&m1,&h2,&m2,&n))
    {
        int h=h2-h1;
        if(m2<m1) {
            h--;
            W=(m2+60-m1)+h*60;
        }
        else W=m2-m1+h*60;
        for(int i=1;i<=n;i++){
            scanf("%d%d%d",&a[i],&b[i],&c[i]);
        }
        solve();
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值