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

背包问题总结

时间:2023-07-23 22:12:40浏览次数:51  
标签:总结 背包 int max cin 问题 物品 AcWing

背包问题总结

目录

01背包问题

AcWing 2.01背包问题


AcWing 打卡
另外的参考

//01背包问题——每件物品最多只用一次 

/*
//二维动态规划

分析:

    f[i][j] 表示只看前i个物品,总体积是j的情况下,总价值最大是多少。

    result = max{f[n][0~V]}     //答案

    f[i][j]:
        1. 不选第 i 个物品,f[i][j] = f[i-1][j]
        2. 选第 i 个物品,f[i][j] = f[i-1][j-v[i]]+w[i]
    f[i][j] = max{1. 2. }

    f[0][0] = 0

    时间复杂度:O(n^2)


代码:

#include <bits/stdc++.h>
using namespace std;
const int N=1010;
int n,m;
int f[N][N];
int v[N],w[N];
int main()
{
    //输入
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        cin>>v[i]>>w[i];
    
    //f[0][0]=0;    // f属于全局变量,不需要再次初始化
    
    //dp过程
    for(int i=1;i<=n;i++)
        for(int j=0;j<=m;j++)
        {
            f[i][j]=f[i-1][j];
            if(j>=v[i])
                f[i][j]=max(f[i][j],f[i-1][j-v[i]]+w[i]);
        }
    
    
    ////寻找答案 result = max{f[n][0~m]}
    //int res=0;
    //for(int i=0;i<=m;i++)
    //    res=max(res,f[n][i]);
    //
    ////输出
    //cout<<res<<endl;
    
    
    //经分析,f[n][m]值最大
    cout<<f[n][m]<<endl;
    
    //结束
    return 0;
}
*/



/*
//一维优化:
分析:
    f[i]表示总体积是j的情况下,总价值最大是多少。
注意:
    需要倒着来(参考:https://www.luogu.com.cn/problem/solution/P1048)

*/

#include <bits/stdc++.h>
using namespace std;
const int N=1010;
int n,m;
int f[N];
int v[N],w[N];
int main()
{
    //输入
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        cin>>v[i]>>w[i];
    
    //f[0][0]=0;    // f属于全局变量,不需要再次初始化
    
    //dp过程
    for(int i=1;i<=n;i++)
        for(int j=m;j>=v[i];j--)
            f[j]=max(f[j],f[j-v[i]]+w[i]);
    
    
    //经分析,f[m]值最大
    cout<<f[m]<<endl;
    
    //结束
    return 0;
}

完全背包问题

AcWing 3.完全背包问题


AcWing 打卡

// 完全背包——每件物品有无数个

/*
//朴素写法
分析:
动态规划:
    1. 状态表示——f[i,j]
        (1). 集合:所有只考虑前i个物品,且总体积不大于j的所有选法
        (2). 属性:Max
    2. 状态计算——集合的划分
        方法:按第i个物品选了多少个划分(0,1,2,3,...,k-1,k)
        (1). 选0个:f[i-1,j]
        (2). 选k个:
            曲线救国:
                %1· 去掉k个物品i
                %2· 求Max,f[i-1,j-k*v[i]]
                %3· 再加回来k个物品i
            f[i,j]=f[i-1,j-v[i]*k]+w[i]*k
代码:

//此算法最坏时间复杂度为:O(10^9)
//所以可能过不了(看评测机忙不忙hhh,偶尔能过)

#include <bits/stdc++.h>

using namespace std;

const int N=1010;

int n,m;
int v[N],w[N];
int f[N][N];

int main()
{
    scanf("%d%d",&n,&m); //cin>>n>>m;
    for(int i=1;i<=n;i++)
        scanf("%d%d",&v[i],&w[i]); //cin>>v[i]>>w[i];
    
    for(int i=1;i<=n;i++)
        for(int j=0;j<=m;j++)
            for(int k=0;k*v[i]<=j;k++) //注意:k不能无限大
                f[i][j]=max(f[i][j],f[i-1][j-v[i]*k]+w[i]*k); //找最大
                
    cout<<f[n][m]<<endl;
    
    return 0;
}
*/

/*
//优化:
分析:
        f[i,j]=f[i-1,j-v[i]*k]+w[i]*k
    f[i,j]=Max( f[i-1,j] , f[i-1,j-v]+w , f[i-1,j-2v]+2w , f[i-1,j-3v]+3w , ... )
    f[i,j-v]=Max(          f[i-1,j-v] ,   f[i-1,j-2v)+w ,  f[i-1,j-3v]+2w , ...... )
    
    所以:
        f[i,j]=Max(f[i-1,j],f[i,j-v]+w)

代码:
【如下】

#include <bits/stdc++.h>

using namespace std;

const int N=1010;

int n,m;
int v[N],w[N];
int f[N][N];

int main()
{
    scanf("%d%d",&n,&m); //cin>>n>>m;
    for(int i=1;i<=n;i++)
        scanf("%d%d",&v[i],&w[i]); //cin>>v[i]>>w[i];
    
    for(int i=1;i<=n;i++)
        for(int j=0;j<=m;j++)
        {
            f[i][j]=f[i-1][j];
            if(j>=v[i])
                f[i][j]=max(f[i][j],f[i][j-v[i]]+w[i]);
        }
                
    cout<<f[n][m]<<endl;
    
    return 0;
}
*/

/*
//一维实现(最优)
//过程类似与01背包
    01背包:f[i,j]=Max(f[i-1,j],f[i-1,j-v]+w)
    完全~: f[i,j]=Max(f[i-1,j],f[i,j-v]+w)
//  01~是i-1,完全~是i

代码:
【如下】
*/

#include <bits/stdc++.h>

using namespace std;

const int N=1010;

int n,m;
int v[N],w[N];
int f[N];

int main()
{
    scanf("%d%d",&n,&m); //cin>>n>>m;
    for(int i=1;i<=n;i++)
        scanf("%d%d",&v[i],&w[i]); //cin>>v[i]>>w[i];
    
    for(int i=1;i<=n;i++)
        for(int j=v[i];j<=m;j++)
            f[j]=max(f[j],f[j-v[i]]+w[i]); //不存在01背包问题,完全背包本来就是f[i][]
                
    cout<<f[m]<<endl;
    
    return 0;
}

注意:如果状态转移时,用的是上次循环的结果(即 f[i-1][j])去一维时应倒序,否则(即 f[i][j])去一维时应正序。

多重背包问题

朴素版本

AcWing 4. 多重背包问题 I


AcWing 打卡

//多重背包——每件物品有一个具体数量s[i]
/*
分析:
    动态规划:
        一、状态表示  f[i,j]
            1. 集合:所有只从前i个物品中选,并且总体积不超过j的选法
            2. 属性:Max
        二、状态计算
            方法:按第i个物品选多少个划分集合(0,1,2,3,...,s[i])
            //与完全背包相似
            状态转移方程:
                f[i][j] = max(f[i-1][j-v[i]*k]+w[i]*k); (k=0,1,2,3,...,s[i])
            
朴素版本代码(暴力写法)://最坏时间复杂度O(n*m*s[i])
【如下】
*/

#include <bits/stdc++.h>

using namespace std;

const int N=110;

int n,m;
int v[N],w[N],s[N];
int f[N][N];

int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        cin>>v[i]>>w[i]>>s[i];
    
    for(int i=1;i<=n;i++)
        for(int j=0;j<=m;j++)
            for(int k=0;k<=s[i]&&k*v[i]<=j;k++) //k有两个条件
                f[i][j]=max(f[i][j],f[i-1][j-v[i]*k]+w[i]*k); //取最大值
    
    cout<<f[n][m]<<endl;
    
    return 0;
}

优化版本

AcWing 5. 多重背包问题 II


AcWing 打卡

参考

//多重背包优化版本(暴力版本将会TLE)
/*

分析:
        原方程:f[i][j] = max(f[i-1][j-v[i]*k]+w[i]*k); (k=0,1,2,3,...,s[i])
    不能以完全背包的方法进行优化(会多出一项)
    
    二进制优化方式:
        主要思想:
            1. 将一个物品的数量按二进制的方式分为(log s[i])份(数量、价值、体积一起分)
                最终将分为:1,2,4,8,...,2^k,c  ( 2^(k+1)>s[i] , c<2^k )
            2. 按01背包实现
        【具体见视频hh】
        
代码:
    【如下】
*/

#include <bits/stdc++.h>

using namespace std;

const int N=12010,M=2010; //物品数量需要上取整, N=1000*log(2000)=12000; M为体积(用于动态规划), M=2000

int n,m;
int v[N],w[N];
int f[M];

int main()
{
    cin>>n>>m;
    
    int cnt=0; //分组的组别
    for(int i=1;i<=n;i++)
    {
        int a,b,s; //第i个物品的体积、价值和数量
        cin>>a>>b>>s;
        int k=1; //组别里面的个数,从1开始分
        while(k<=s)
        {
            cnt++; //组别先增加
            v[cnt]=a*k; //整体体积
            w[cnt]=b*k; // 整体价值
            s-=k; // s要减小
            k*=2; // 组别里的个数增加(二进制2^k)
        }
        if(s>0) //剩余的一组 —— 剩下的s就是分析里的c
        {
            cnt++;
            v[cnt]=a*s;
            w[cnt]=b*s;
        }
    }
    
    n = cnt ; //枚举次数正式由个数变成组别数

    //01背包一维优化
    for(int i=1;i<=n;i++)
        for(int j=m;j>=v[i];j--)
            f[j]=max(f[j],f[j-v[i]]+w[i]);

    cout<<f[m]<<endl;
    
    return 0;
    
}

分组背包问题

AcWing 9.分组背包问题


AcWing 打卡

/*
分组背包 —— 每组物品有若干个,同一组内的物品最多只能选一个。

动态规划:
    状态表示f[i,j]:
        集合:只从前i组物品中选,且总体积不大于j的所有选法
        属性:Max
    状态计算:
        f[i-1, j-v[i,k]] + w[i, k]


*/

// 本处直接给出一维优化代码:

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 110;

int n, m;
int v[N][N], w[N][N], s[N];
int f[N];

int main()
{
    cin >> n >> m;

    for (int i = 1; i <= n; i ++ )
    {
        cin >> s[i];
        for (int j = 0; j < s[i]; j ++ )
            cin >> v[i][j] >> w[i][j];
    }

    for (int i = 1; i <= n; i ++ )
        for (int j = m; j >= 0; j -- )
            for (int k = 0; k < s[i]; k ++ )
                if (v[i][k] <= j)
                    f[j] = max(f[j], f[j - v[i][k]] + w[i][k]);

    cout << f[m] << endl;

    return 0;
}

标签:总结,背包,int,max,cin,问题,物品,AcWing
From: https://www.cnblogs.com/MingruiYang/p/17575793.html

相关文章

  • 解决tyopora传图片到博客园的问题(本地图片无法直接复制)
    1.问题我们这里的是本地路径,但我们需要html路径解决方法见https://www.bilibili.com/video/BV1Rv4y1Y7KH?p=5&vd_source=f6ddd7329bd73c42abb316ba2331ff7b2.解决方法dotnet-cnblogproc-f1.启用.NET...3.5服务2.安装指定文件3.管理员身份打开终端配置1.博客ID2.......
  • 20230723练习总结
    CF923DPickingStrings当变化规则不好分析的时候可以考虑自己随便模拟一下变化过程,总结浓缩出一些等价且更简单的变化规则。尝试推出几个比较简单的变化关系:\(\texttt{B}\rightarrow\texttt{AC}\rightarrow\texttt{AAB}\rightarrow\texttt{AAAC}\rightarrow\texttt{C}\right......
  • 为什么多线程下会有线程安全问题
    原子性:加锁(乐观锁CAS、悲观锁)原子性是指一个操作或一系列操作要么全部执行成功并且不被中断,要么完全不执行,没有中间状态。在多线程或并发环境下,如果一个操作是原子性的,那么其他线程不会在该操作执行过程中看到该操作的部分结果。原子性是为了保证操作的一致性和正确性。例如,一个......
  • window docker desktop 安装失败的问题
     -AnunexpectederrorwasencounteredwhileexecutingaWSLcommand.Commoncausesincludeaccessrightsissues,whichoccurafterwakingthecomputerornotbeingconnectedtoyourdomain/activedirectory.-PleasetryshuttingWSLdown(wsl--shutdow......
  • clang中参数入栈顺序问题
    在clang中,函数调用的参数入栈顺序是从右往左,而在gcc中参数入栈顺序是从左往右。遇到这个问题的场景是现有项目中有一段代码,在gcc下编译后执行是没问题的,但是在clang下执行却一直报错,通过debug后发现,是由于函数参数的入栈顺序不同导致的。问题代码的逻辑类似于以下demo:#include......
  • windows 上书写shell脚本上传远程服务器注意问题
    ①权限问题:上传脚本,没有可执行权限,解决:chmod-u=rwx*.sh;②文件格式问题:windows上的是dos格式,linux上需要的是unix格式,解决:vim修改我们的脚本,执行以下命令 :setff? 查看脚本格式,如果是fileformat=dos就说明是dos格式需要修改为unix格式:setff=unix然后wq ......
  • 【LuoGU 1273】有线电视网——树上分组背包问题
    有线电视网题目描述某收费有线电视网计划转播一场重要的足球比赛。他们的转播网和用户终端构成一棵树状结构,这棵树的根结点位于足球比赛的现场,树叶为各个用户终端,其他中转站为该树的内部节点。从转播站到转播站以及从转播站到所有用户终端的信号传输费用都是已知的,一场转播的总......
  • Django:admin后台汉化问题
    Django:admin后台汉化问题1、设置admin站点中文显示,即汉化admin后台管理站点。方法一:修改settings文件LANGUAGE_CODE='en-us'TIME_ZONE='UTC'更改为:LANGUAGE_CODE='zh-Hans'TIME_ZONE='Asia/Shanghai'方法二:添加中间件(注意:中间件是有顺序的,不要随意更改。......
  • DecimalFormat 四舍五入问题
    DecimalFormat函数默认的四舍五入的方法是银行家算法(RoundingMode.HALF_EVEN),跟一般的四舍五入的方法不同可以用String.format("%.6f",d)来代替也可以指定 df.setRoundingMode(RoundingMode.HALF_UP)为正常四舍五入;ps银行家算法:四舍六入五考虑,五后非零就进一,五后为零看奇偶,......
  • 杂文-关于码风的问题
    我的分类和推荐是否有空格我更喜欢有空格的比如说这一串x=(x*2)+__builtin_popcount(x)&1,x/=res,x+=mod,x%=mod;乱写的,这样看起来有点难受qwq当我们加了空格以后,会变成:x=(x*2)+__builtin_popcount(x)&1,x/=res,x+=mod,x%=mod;这样感觉会舒服一点,不过......