首页 > 其他分享 >背包问题

背包问题

时间:2023-04-09 23:44:31浏览次数:60  
标签:背包 int 复杂度 问题 maxn nv include dp

复健\(Day1\)

今天复习基础背包问题,在\(ACWing\)上使用挑战模式去打模板,提高打代码速度

\(01\)背包

解决每种物品只有一样的情况
时间复杂度\(O(nV)\),空间复杂度优化后为\(O(V))\)
空间优化的代码中体积一维从后往前更新,因为其递推公式为\(dp[i][j]=max(dp[i-1][j],dp[i-1][j-v[i]]+w[i])\),若我们从前往后更新那么相当于改变了\(dp[i-1][j-v[i]]\)的值,这样会对后面的更新造成影响

#include<iostream>
#include<cstdio>
#define maxn 1010
using namespace std;

int dp[maxn],v[maxn],w[maxn];
int n,V;

int main()
{
    cin>>n>>V;
    for(int i=1;i<=n;i++) cin>>v[i]>>w[i];
    for(int i=1;i<=n;i++)
    {
        for(int j=V;j>=v[i];j--) dp[j]=max(dp[j],dp[j-v[i]]+w[i]);
    }
    printf("%d\n",dp[V]);
    return 0;
}

多重背包

解决每种物品有确定值的情况

二进制优化

进行二进制优化后,时间复杂度由\(O(nVs)\)优化为\(O(nVlogs)\)
之所以能进行二进制优化的原因:对于某种数量\(s\),我们不需要从\(0\)开始枚举其选择的数量,而是采用分组打包的方式\(:2\ ^0,2\ ^1,...2\ ^k\),直至\(s-2\ ^k+1\leqslant 0\)时,无法再用\(2\ ^t\)的形式表示,那么最后一组就为\(s-2\ ^k+1\)个,这样我们的枚举数就从原本的\(s\)优化为了\(logs\)了
体积一维从后往前更新,因为其递推公式为\(dp[i][j]=max(dp[i-1][j],dp[i-1][j-v[i]]+w[i])\)

#include<iostream>
#include<cstdio>
#define maxn 2010
using namespace std;


int dp[maxn],v[maxn],w[maxn],s[maxn],nv[maxn],nw[maxn],cnt;
int n,V;

int main()
{
    cin>>n>>V;
    for(int i=1;i<=n;i++)
    {
        cin>>v[i]>>w[i]>>s[i];
        int k;
        for(k=1;s[i]-(1<<k)+1>=0;k++)
        {
            nv[++cnt]=v[i]*(1<<(k-1));
            nw[cnt]=w[i]*(1<<(k-1));
        }
        k--;
        nv[++cnt]=v[i]*(s[i]-(1<<k));
        nw[cnt]=w[i]*(s[i]-(1<<k));
    }
    for(int i=1;i<=cnt;i++)
    {
        for(int j=V;j>=nv[i];j--) dp[j]=max(dp[j],dp[j-nv[i]]+nw[i]);
    }
    printf("%d\n",dp[V]);
    return 0;
}

优先队列优化

https://www.acwing.com/solution/content/53507/
上面是写的很清楚的解析
滚动数组的长度为\(s[i]+1\),所有满足\(j\equiv r(modv[i])\)进行维护从而得出最大值
最后时间复杂度为\(O(nV)\),空间复杂度为\(O(v)\)

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

const int N=1010,M=20010;

int g[M],f[M],q[M];
int v[N],w[N],s[N];
int n,V;

int main()
{
    cin>>n>>V;
    for(int i=1;i<=n;i++) cin>>v[i]>>w[i]>>s[i];
    for(int i=1;i<=n;i++)
    {
        memcpy(g,f,sizeof(g));
        for(int r=0;r<v[i];r++)
        {
            int hh=0,tt=-1;//每次都是新的队列
            for(int j=r;j<=V;j+=v[i])
            {
                while(hh<=tt&&j-q[hh]>s[i]*v[i]) hh++;//最开头那个f值最大的v,我们的j减去它之后剩余的体积过大,其实没必要存,所以出队
                while(hh<=tt&&g[q[tt]]+(j-q[tt])/v[i]*w[i]<=g[j]) tt--;//最后的那个元素并不比g[j]优,无法更新别的元素,所以出队
                q[++tt]=j;
                f[j]=g[q[hh]]+(j-q[hh])/v[i]*w[i];//更新最前端的那个元素
            }
        }
    }
    printf("%d\n",f[V]);
    return 0;
}

完全背包

解决物品数量为无穷多个的情况
时间复杂度为\(O(nV)\),空间复杂度优化为\(O(V)\)
它的体积一维从前往后更新,原因是递推公式为\(dp[i][j]=max(dp[i-1][j],dp[i][j-v[i]]+w[i])\)它是由\(dp[i][j-v[i]]+w[i]\)更新而来,所以我们要先更新小的\(j\),这样才能进一步更新后面的\(j\)

#include<iostream>
#include<cstdio>
#define maxn 2010
using namespace std;

int dp[maxn],v[maxn],w[maxn];
int n,V;

int main()
{
    cin>>n>>V;
    for(int i=1;i<=n;i++) cin>>v[i]>>w[i];
    for(int i=1;i<=n;i++)
    {
        for(int j=v[i];j<=V;j++) dp[j]=max(dp[j],dp[j-v[i]]+w[i]);
    }
    printf("%d\n",dp[V]);
    return 0;
}

混合背包

很简单的,这种情况就是判断此种物品是有一个还是有确定个,还是有无穷多个,使用不同处理即可

#include<iostream>
#include<cstdio>
#define maxn 1010
using namespace std;

int dp[maxn],v[maxn],w[maxn],s[maxn],nv[maxn],nw[maxn],cnt;
int n,V;

int main()
{
    cin>>n>>V;
    for(int i=1;i<=n;i++)
    {
        cin>>v[i]>>w[i]>>s[i];
        if(s[i]==-1)
        {
            for(int j=V;j>=v[i];j--) dp[j]=max(dp[j],dp[j-v[i]]+w[i]);
        }
        else if(s[i]==0)
        {
            for(int j=v[i];j<=V;j++) dp[j]=max(dp[j],dp[j-v[i]]+w[i]);
        }
        else
        {
            int k;
            cnt=0;
            for(k=1;s[i]-(1<<k)+1>0;k++)
            {
                nv[++cnt]=v[i]*(1<<(k-1));
                nw[cnt]=w[i]*(1<<(k-1));
            }
            k--;
            nv[++cnt]=v[i]*(s[i]-(1<<k)+1);
            nw[cnt]=w[i]*(s[i]-(1<<k)+1);
            for(int j=1;j<=cnt;j++)
            {
                for(int m=V;m>=nv[j];m--) dp[m]=max(dp[m],dp[m-nv[j]]+nw[j]);
            }
        }
    }
    printf("%d\n",dp[V]);
    return 0;
}

标签:背包,int,复杂度,问题,maxn,nv,include,dp
From: https://www.cnblogs.com/iwillenter-top1/p/17299588.html

相关文章

  • 优先级队列PriorityQueue在算法问题中的使用
    文章目录优先级队列介绍与优先级队列有关的习题[179.最大数][918.环形子数组的最大和][1094.拼车][264.丑数II]前k个出现频率最高的数字用优先级队列合并k个有序链表滑动窗口的最大值其他:对二维数组自定义排序优先级队列介绍优先队列一般基于二叉堆实现,二叉堆:堆的根节点的优......
  • 算法类问题
    木棒三角形(枚举)#include<iostream>#include<stdlib.h>usingnamespacestd;intmain()//木棒三角形有n根木棍挑出其中三根构成直角三角形输出面积最大的三角形面积输入n再输入每根三角形长度,n<100{ intn;//输入n根木棍再分别输入每根木棍的长度限制了n数量小于100 i......
  • 常见问题问答
    1.Promise底层原理promise是一种用于处理异步操作的javascript对象,底层原理基于回调函数、事件监听和状态机等技术。在promise对象创建时,会初始化一个状态,通常有三种状态:pending(进行中)、fulfilled(已完成)和rejected(已拒绝)。当使用promise封装的异步操作成功完成时,promise状态将......
  • golang 编译碰到问题 Package python-2.7 was not found in the pkg-config search pa
    golang运行单测或者编译程序时提示需要配置PKG_CONFIG_PATH环境变量,原因是在程序里使用了go-python包,要求运行环境有python2.7,并设置PKG_CONFIG_PATH环境变量,解决方案如下:#pkg-config--cflags--python-2.7Packagepython-2.7wasnotfoundinthepkg-configsear......
  • Ubuntu系统Flameshot使用问题
    Ubuntu系统Flameshot使用问题系统:Ubuntu22.04问题:使用Flameshot,每次都会先截取整个屏幕,提示需要先分享,再使用Flameshot的功能安装Flameshotsudoaptinstallflameshot先说解决方案开机用户登录时,右下角有设置桌面环境,默认是Ubuntu,修改为UbuntuonXorg问题使用Flame......
  • Arrays.asList使用的一些问题
    java.util.Arrays.asList()List是一种很有用的数据结构,如果需要将一个数组转换为List以便进行更丰富的操作的话,可以这么实现:String[]myArray={"Apple","Banana","Orange"};List<String>myList=Arrays.asList(myArray);List<String>myList=Arra......
  • 前端报错时如何排查问题
    前端页面报错: 1、页面报错500,首先我们可以知道是服务端的问题,需要去看下服务端的报错信息:2、首先我们查看下前端是否给后端传了id: 我们可以看到接口是把ID返回了,就需要再看下p_id是什么情况了 3、我们再次请求,把p_id进行打印,看下具体是什么:put接口代码classPutV......
  • FastCFS:再谈 选主 与 过半写:续:2节点群集 默认配置下,十分不可靠,几乎100%会发生脑裂问题
     如题:仅能由于测试。千万不要用于生产环境!“选主” 通常能够完成,无法是否有vote参与;问题在于:“过半写”的any或auto模式(即隐含的smart模式)在成功“选主“后,会运行在单节点server的群集模式下,此时,根本就无法且没有完成正常意义上的数据层的主从同步,即必然发生脑裂!数据就不一......
  • (已解决)安装PyMySQL出现问题--'pip' 不是内部或外部命令,也不是可运行的程序 或批处理文
    问题描述:输入cmd,进入命令窗口,输入pipinstallpymysql时候出现下面的问题: 然后进入python环境中去输入还是报错:问题原因:环境变量配置出错,cmd下无法调用pip程序。解决办法:①首先退出python环境,输入命令:exit() ②然后去电脑里面找到python的安装位置,如图类似这样的文件......
  • mat1*mat的问题
    1x=self.layer5(x)#[6413]2#print("layer5",x.shape)3x=x.view(x.size(0),-1)4#print("view",x.shape)5x=self.fc(x)6returnx#这里layer5是一个卷积层#:self.layer5=n......