首页 > 其他分享 >01背包与完全背包

01背包与完全背包

时间:2024-11-06 22:19:41浏览次数:3  
标签:状态 背包 const int max 完全 01 include

背包套路

最大分成两步骤:1.状态表示  2. 状态计算

1.状态表示

状态表示从两个角度来思考 :(1)集合 (2) 属性

(1)集合 : 满足某中条件下的所有选法的集合

(2)属性:最大值 / 最小值 / 数量

2.状态计算:

所谓状态计算就是集合的划分,满足两种原则:(1)不重 (2)不漏

对与求最大值和最小值的问题可以重复,但是求方案数量的时候不能重复


01背包

每件物品最多只能选一次(也可以不选)

思路:

状态表示: f[ i ] [ j ]

(1)集合:只从前i个物品当中选,并且总体积不超过 j 所有选法

(2) 属性: 所有选法当中的最大价值(MAX)

状态计算:

(1) f[i - 1][j] : 不包含第 i 个物品的最大价值

(2) f[i - 1][j - v[i]] + w[i]: 包含第 i 个物品的最大价值

二维状态下:
#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(){
    cin >> n >> m;
    
    for(int i = 1; i <= n; 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-1][j-v[i]] + w[i]);
        }
    }
    cout << f[n][m];        //前n个物品中,体积不超过m的最大价值
    
    return 0;
}

优化过程

for(int i = 1; i <= n; i++){
  for(int j = v[i]; j <= m; j++){  //j是从小到大进行枚举的

    f[j] = max(f[j], f[j - v[i]] + w[i]);
   //在这一步骤当中,j - v[i] 是严格小于 j 的,
  //因此枚举到j 之前j - v[i] 会被先更新掉,
 //这样会影响后续的答案

 //相当于 f[i][j] = max(f[i][j],f[i][j-v[i]] + w[i]),这个方程与原来的方程不一样
  } 
}
-------------------------------------------------------

//解决方法: 我们只要把 j 从大到小枚举即可

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]);
  }
}
一维状态下:
#include <bits/stdc++.h>
using namespace std;

const int N = 1010;

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

int main(){
    cin >> n >> m;
    
    for(int i = 1; i <= n; i++){
        cin >> v[i] >> w[i];
    }
    
    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;
}

完全背包

每件物品可以选无限次

思路:

朴素做法O(n^3)
#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(){
    cin >> n >> m;
    
    for(int i = 1; i <= n; 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++){
                f[i][j] = max(f[i][j],f[i - 1][j - k * v[i]] + k * w[i]);
            }
        }
    }
    cout << f[n][m] << endl;
    return 0;
}

方程的优化过程:

二维状态下进行优化: 
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 1010;

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

int main()
{
    cin >> n >> m;
    for (int i = 1; i <= n; 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背包:  f[i][j] = max(f[i - 1][j] , f[i - 1][j] - v[i]] + w[i]);

完全背包:f[i][j] = max(f[i - 1][j] , f[i][j -v[i]] + w[i]);

 经过观察,我们很容易看出完全背包与01 背包的差距在于,f[i][j - v[i]] + w[i] 这一部分。

 这就刚好于上面分析过的 01背包相反,完全背包恰好用到的是同一层,因此 j 从小到大枚举即可

一维状态下:
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 1010;

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

int main()
{
    cin >> n >> m;
    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 <= m; j++){
           f[j] = max(f[j],f[j - v[i]] + w[i]);
       }
   }

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

标签:状态,背包,const,int,max,完全,01,include
From: https://blog.csdn.net/2301_81182847/article/details/143579870

相关文章

  • LOJ6119 「2017 山东二轮集训 Day7」国王
    题意给定一颗树,每个点有权值\(1\)和\(-1\),称一条路径是好的当且仅当路径上所有点的权值和为\(0\)。求连续编号区间\([l,r]\)使得两个点都在\([l,r]\)的好路径比两个点都不在\([l,r]\)的好路径数严格多的方案数。\(n\le10^5\)。Sol两个端点都在区间内不好做,......
  • 代码随想录算法训练营第十八天|leetcode530.二叉搜索树的最小绝对差、leetcode501.二
    1leetcode530.二叉搜索树的最小绝对差题目链接:530.二叉搜索树的最小绝对差-力扣(LeetCode)文章链接:代码随想录视频链接:你对二叉搜索树了解的还不够!|LeetCode:98.验证二叉搜索树_哔哩哔哩_bilibili思路:定义一个极大值作为结果,然后在中序遍历过程中进行比较出结果1.1自己的......
  • 数据处理与统计分析——01-Numpy的属性&ndarray数组创建
    Numpy的属性Numpy简介NumPy(NumericalPython)是Python数据分析必不可少的第三方库NumPy的出现一定程度上解决了Python运算性能不佳的问题,同时提供了更加精确的数据类型,使其具备了构造复杂数据类型的能力。本身是由C语言开发,是个很基础的扩展,NumPy被Python其它科学计算包作......
  • 校园资讯平台微信小程序(30143)
     有需要的同学,源代码和配套文档领取,加文章最下方的名片哦一、项目演示项目演示视频1项目演示视频2二、资料介绍完整源代码(前后端源代码+SQL脚本)配套文档(LW+PPT+开题报告)远程调试控屏包运行三、技术介绍Java语言SSM框架SpringBoot框架Vue框架JSP页面Mysql数据库IDEA/Ecl......
  • CF1270 Good Bye 2019
    Dashboard玩构造玩的,服了。A拥有最大牌的必胜。linkB若相邻的差\(\ge2\)则有解,否则根据变化连续性一定无解。linkC加两个数,第一个数为之前所有数的异或和。加进来之后异或为0。第二个数为加完第一个数之后的和。linkD考虑\(k=n-1\)时,分别询问除去每个数之后的第\(......
  • AI预测福彩3D采取888=3策略+和值012路+胆码+通杀1码预测11月6日新模型预测第132弹
             经过100多期的测试,当然有很多彩友也一直在观察我每天发的预测结果,得到了一个非常有价值的信息,那就是9码定位的命中率非常高,100多期一共只错了12次,这给喜欢打私房菜的朋友提供了极高价值的预测结果~当然了,大部分菜友还是走的正常渠道,因此,得想办法进行缩水,尽......
  • AI预测体彩排3采取888=3策略+和值012路+胆码+通杀1码测试11月6日升级新模型预测第126
             经过100多期的测试,当然有很多彩友也一直在观察我每天发的预测结果,得到了一个非常有价值的信息,那就是9码定位的命中率非常高,已到达90%的命中率,这给喜欢打私菜的朋友提供了极高价值的预测结果~当然了,大部分菜友还是走的正常渠道,因此,得想办法进行缩水,尽可能少的......
  • CF的背包DP (备用笔记)
    源自vjudge上找到题目,都是背包DP的变式------(推荐点点前两个字......
  • CF2001 题解
    A给定循环数组,每次操作时,设当前大小为m。选择$i\in[0,m)$,若满足$a_i\lea_{i+1\bmodm}$,则可删除$a_i,a_{i+1\bmodm}$中的任意一个。求最小的操作次数,使得数组中所有元素都相等。$n\le100$操作非常强,除了两个相邻位置相等的情况,可以删除任意元素。然而所有位置都......
  • WC2010 重建计划
    谨以此纪念这个废物逝去的一天。别看它是一道黑题但是它不配。首先它长得很像分数规划,直接二分答案,这样就把每条边的边权看成了\(V(e)-\text{mid}\),然后你希望求经过边数在\([L,U]\)之间的最长路径,判断它是否\(\ge0\)。考虑一个暴力\(dp_{i,j}\)表示\(i\)作为链顶,其子......