首页 > 编程语言 >周六900C++班级-2022-11-19 01背包

周六900C++班级-2022-11-19 01背包

时间:2022-11-23 14:15:37浏览次数:49  
标签:11 900 01 int 件物品 重量 背包 价值 dp

背包问题关系图

 

 

问题描述

若有 N 件物品和一个最多能装重量为 W 的背包,一个物品只有两个属性:重量和价值。第i件物品的重量是weight[i],得到的价值是value[i] 。假设每件物品只能用一次,将哪些物品装入背包里物品价值总和最大?

注意:0-1 背包问题无法使用贪心算法来求解,也就是说,不能按照先添加性价比最高的物品来达到最优,因为这种方式可能造成背包空间的浪费,从而无法达到最优。


 

 

基本思路

上述问题是典型的动态规划,这里有两个可变量:重量和价值,我们定义dp[i][j]:前i件物品重量不超过j时背包能达到的最大价值,背包的初始状态是最终目标是dp[N][W],即前N件物品重量不超过W时背包能达到的最大价值。

设第 i 件物品重量为 w,价值为 v,根据第 i 件物品是否添加到背包中,可以分两种情况讨论:

  • 第 i 件物品没添加到背包,最大价值:dp[i][j] = dp[i - 1][j]
  • 第 i 件物品添加到背包中:dp[i][j] = dp[i - 1][j - w] + v

第 i 件物品可添加也可以不添加,取决于哪种情况下最大价值更大。因此,0-1 背包的状态转移方程为:
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - w] + v)

#include<bits/stdc++.h>
using namespace std;
int dp[30][30005];
int n,m;
int w[30],v[30];//w重量,v价值 
int main()
{
    cin>>m>>n;
    for(int i=1;i<=n;i++)
    {
        int x,y;
        cin>>x>>y;
        w[i] = x; //重量 = 价钱 
        v[i] = x*y; //价值 = 价钱x*重要度y 
    }
    //以下是01背包环节
    for(int i=1;i<=n;i++) //先循环物品
    {
        for(int j=1;j<=m;j++) //再循环容量
        {
            if(j-w[i]>=0) 
                dp[i][j] = max(dp[i-1][j],dp[i-1][j-w[i]]+v[i]);
            else //不能取第i个物品时的最大值与上一层i-1相同
                dp[i][j] = dp[i-1][j];
        } 
    } 
    cout<<dp[n][m];
     return 0;
}

 优化

由于dp[i][j]的值只与dp[i-1][0,...,j-1]有关,可以采用动态规划常用的优化方法对空间进行优化(即去掉dp的第一维)。因此,0-1 背包的状态转移方程为: dp[j] = max(dp[j], dp[j - w] + v)

特别注意:为了防止上一层循环的dp[0,...,j-1]被覆盖,循环的时候 j 只能逆向遍历。优化空间复杂度:

#include<bits/stdc++.h>
using namespace std;
int dp[30005]; //优化后dp数组为最大背包容量 
int n,m;
int w[30],v[30];//w重量,v价值 
int main()
{
    cin>>m>>n;
    for(int i=1;i<=n;i++)
    {
        int x,y;
        cin>>x>>y;
        w[i] = x; //重量 = 价钱 
        v[i] = x*y; //价值 = 价钱x*重要度y 
    }
    //以下是01背包环节
    for(int i=1;i<=n;i++) //先循环物品
    {
        for(int j=m;j>=1;j--) //再循环容量,一维背包为防止覆盖先前数据要逆序循环 
        {
            dp[j] = max(dp[j],dp[j-w[i]]+v[i]); //一维背包的状态转移方程 
        } 
    } 
    cout<<dp[m];
     return 0;
}
01背包内循环理解:还原成二维的dp就很好理解,一维的dp是二维dp在空间上进行复用的结果。dp[i]=f(dp[i-num]),等式的右边其实是二维dp上一行的数据,应该是只读的,在被读取前不应该被修改。如果正序的话,靠后的元素在读取前右边的dp有可能被修改了,倒序可以避免读取前被修改的问题。

标签:11,900,01,int,件物品,重量,背包,价值,dp
From: https://www.cnblogs.com/jyssh/p/16918060.html

相关文章

  • FR11 webservice程序数据集
    packagecom.fr.data;importcn.hutool.core.lang.Console;importcn.hutool.http.webservice.SoapClient;importcn.hutool.json.JSONArray;importcn.hutool.json.......
  • 11.23.1
    #include<stdio.h>#include<string.h>intmain(){intl1,l2,i,j; chara[50]; gets(a); l1=strlen(a); for(i=0;i<l1;i++) {printf("%c",a[i]); } for(i=l1-1;i>=......
  • 「WOJ 4701」Walk 虚点建图+01bfs
    前言模拟赛中,yzh遇到了这道题,但由于yzh没有学过01bfs。。。所以就一直在优化这道题,导致浪费了很长时间(但nfls的数据太水,dij和spfa都能过)Description给你一个\(n\)个......
  • 支持安卓11.0操作系统——《XY6853ZA 5G AI安卓核心板》!
        产品结构概括:《XY6853ZA5GAI安卓核心板》基于联发科最新5G手机芯片自主研发MT6853(天玑720)平台,支持AI/SA/NSA双模5G全网通。内构性能结构为研发人员自主研发的......
  • 11月23日推特过滤总结v2
    推特用户:@elonmusk推特内容:FoundinclosetatTwitterHQfrhttps://t.co/3xSI3KvvHk网址:https://twitter.com/twitter/statuses/1595250835096621057推特用户:@el......
  • 11届双创大赛层层角逐,英码科技勇创佳绩荣获“优胜奖”!
    经过激烈的角逐和路演竞赛,以“创新引领,创业筑梦”为主题的第十一届中国创新创业大赛(广东·广州赛区)暨2022年广州科技创新创业大赛圆满落下帷幕,英码科技初次参赛凭借“AI+边......
  • 随想录(写给那些学校不是985、211的同学们)
       每年的6、7月份都是一年一度的毕业季。按照某些新闻机构的统计数字来说,现在每一年毕业的人数达到了600万之多。然而随着社会经济的放缓、贫富差距的拉开,找工作变得越......
  • 11月22改题(NOIP 模拟赛)
    T1触手思路:第一问很简单,用st表维护区间最小值,再用线段树做区间修改,再单点查询最终的高度,相加即可;第二问是一个贪心,不难发现,对于所有最终的高度,覆盖一段高度连续的区......
  • 【题解】P2303 [SDOI2012] Longge 的问题
    【题解】P2303[SDOI2012]Longge的问题题目链接求\(\displaystyle\sum_{i=1}^n\gcd(i,n)\)将这个柿子展开变复杂,得到\[\displaystyle\sum_{i=1}^{n}\sum_{d\mid......
  • 11月23日总结
    今天干了啥:Python3集合打算干啥:Python3编程第一步代码数:291......