Week 5 背包问题

感想

这周感触很多,从刚开始死活理解不了01背包,连课程视频都看不下去,到到处找资源理解01背包,最终算是对01背包有了初步的认识,后面的完全背包、多重背包、分组背包,在稍微看懂了01背包之后,也起码能看懂在说什么,为什么这么做了。这周起初天天怀疑人生,到后面才算是又慢慢找回自信。这里特别感谢代码随想录,看完他的视频才大概了解了01背包。

下面贴上这周学习的资源:

【精选】动态规划之背包问题(01背包问题、完全背包问题、多重背包问题 I、多重背包问题 II 、分组背包问题)_01背包问题的时间复杂度_小羊努力变强的博客-CSDN博客【精选】多重背包问题---超详细讲解+优化(不懂你揍我)-CSDN博客混合背包二进制优化(伪万能背包模板)_混合背包模板+二进制优化算法描述-CSDN博客信息学奥赛一本通 1270:【例9.14】混合背包-CSDN博客带你学透0-1背包问题!| 关于背包问题,你不清楚的地方,这里都讲了!| 动态规划经典问题 | 数据结构与算法_哔哩哔哩_bilibili

P1833 樱花 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

P1048 采药

#include<iostream>
using namespace std;
int main(){
    int t,m; cin>>t>>m;
    int time[1010],value[1010],dp[1010];
    for(int i=1;i<=m;i++) cin>>time[i]>>value[i];

    for(int i=1;i<=m;i++){
        for(int j=t;j>=time[i];j--){
            dp[j]=max(dp[j],dp[j-time[i]]+value[i]);
        }
    }

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

直接上代码了,01背包用一维数组时要倒序处理,以防重复取出体积比较小的物品。

P1616 疯狂的采药

#include<iostream>
using namespace std;
int main(){
    int t,m; cin>>t>>m;
    long long time[10010],value[10010],dp[10000010];
    for(int i=1;i<=m;i++) cin>>time[i]>>value[i];

    for(int i=1;i<=m;i++){
        for(int j=time[i];j<=t;j++){
            dp[j]=max(dp[j],dp[j-time[i]]+value[i]);
        }
    }

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

代码如上,完全背包处理时要正序,因为要保证每一种物品都能尽可能多取。

P1049 装箱问题

#include<iostream>
using namespace std;
int main(){
    int v,n; cin>>v>>n;
    long long a[100010],dp[100010]={0};
    for(int i=1;i<=n;i++) cin>>a[i];

    for(int i=1;i<=n;i++){
        for(int j=v;j>=a[i];j--)
        dp[j]=max(dp[j],dp[j-a[i]]+a[i]);
    }

    cout<<v-dp[v];
    return 0;
}

 代码如上,这个题相当于value=weight的01背包问题,所以value和weight可用一个数组来表示

P1833 樱花

#include<iostream>
using namespace std;
int gettime(int a,int b,int c,int d){
    int res=c*60+d-(a*60+b);
    return res;
}
int main(){
    int a,b,c,d; char ch1,ch2;
    cin>>a>>ch1>>b>>c>>ch2>>d;
    int n; cin>>n;
    long long time[10010],beautiful[10010],times[10010],dp[10020];
    int ddl=gettime(a,b,c,d);
    for(int i=1;i<=n;i++) cin>>time[i]>>beautiful[i]>>times[i];

    for(int i=1;i<=n;i++){//混合背包
        if(times[i]==0){//完全背包
            for(int j=time[i];j<=ddl;j++) 
            dp[j]=max(dp[j],dp[j-time[i]]+beautiful[i]);
        }
        else if(times[i]==1){//01背包
            for(int j=ddl;j>=time[i];j--)
                dp[j]=max(dp[j],dp[j-time[i]]+beautiful[i]);
        }
        else{//多重背包
            for(int j=ddl; j >= time[i]; j--)
                for(int k = 0; k*time[i] <= j && k <= times[i]; k++)
                    dp[j] = max(dp[j],dp[j-k*time[i]]+k*beautiful[i]);
            }
        }
    
    cout<<dp[ddl];
    return 0;
}

这个题受益匪浅。首先是这个题把01,完全和多重背包都融合到了一起,其次是这个题存在一种二进制优化的处理方式,但是这个我目前跟着敲的结果还不太对,这里先不写。上面的代码思路非常清晰的写出了几种背包的处理方式,那就再说一下几种的异同,一维01和多重是逆序,完全是正序。然后多重背包要多一层for循环用来遍历k,来填满背包。

下面再谈谈二进制优化,有了这个优化,完全和多重背包都可以被转化成01背包,这样就很方便。写一下我到处看,然后按自己理解敲出来的二进制优化代码,但是它结果不对,我到现在还没看出问题在哪。

#include<iostream>
using namespace std;
int gettime(int a,int b,int c,int d){
    int res=c*60+d-(a*60+b);
    return res;
}
int cnt=0;
int main(){
    int aa,bb,cc,dd; char ch1,ch2;
    cin>>aa>>ch1>>bb>>cc>>ch2>>dd;
    int t=gettime(aa,bb,cc,dd);
    int n; cin>>n;
    int time[10010],value[10010],dp[10010];
    for(int i=1;i<=n;i++){
        int t,v,s; cin>>t>>v>>s;
        int k=1;
        while(k<=s){
            time[cnt]=t*k; value[cnt]=v*k;
            s=s-k; k*=2; cnt++;
        }
        if(s){
            cnt++;
            time[cnt]=t*s; value[cnt]=v*s;
        }
    }
    for(int i=1;i<=cnt;i++){
        for(int j=t;j>=time[i];j--){
            dp[j]=max(dp[j],dp[j-time[i]]+value[i]);
        }
    }
    cout<<dp[t];
    return 0;
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值