背包整理(01背包,完全背包,多重背包,分组背包)(待更新)

目录

  • 01背包

    • 优化(空间)
  • 完全背包
    • 优化
  • 多重背包
    • 优化
  • 分组背包

01背包

有N件物品和一个容量为V的背包。第i件物品的价格(即体积,下同)是w[i],价值是c[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

对于每个物品,我们有两种选择:把这个物品放进背包还是不放。
d[i][v]表示前i件物品,恰放入容积为v的背包时的价值总和。
状态转移方程为 \[d[i][v] = \max(d[i - 1][v],d[i - 1][v - w[i]] + c[i])\]

优化(空间)

\[d[v] = \max(d[v],d[v - w[i]] + c[i])(倒序枚举)\]

完全背包

有N件物品和一个容量为V的背包。第i种物品的价格(即体积,下同)是w[i],价值是c[i],每种物品有无限多个。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

用f[i][j]表示前i种背包装入容量为j的背包中所可以获得的最大价值
对于一种物品,只有两种情况
  情况一: 第i件不放进去,这时所得价值为:\[f[i-1][v]\]
  情况二: 第i件放进去,这时,我们需要枚举放进去多少件,设为K,所得价值为:\[f[i-1][v-K*c[i]]+K*w[i]\]
状态转移方程为:\(\max \limits_{0<=K<=v/w[i]} f[i-1][v-K*w[i]]+K*c[i]\)

//最暴力做法
for(int i = 1; i <= n; i++)
    for(int v = V; v >= w[i]; v--)
        for(int k = 1; k <= v/w[i]; k++){
            d[i][v] = max(d[i - 1][v - w[i]*k]+c[i]*k,d[i][v]);
        } 

优化

\[d[v] = max(d[v],d[v - w[i]] + c[i])(正序枚举/对于每种物品循环1次)\]
可以感性理解一下

多重背包

把多重背包转化为01背包 也就是说本来每种物品有有限个,我们把这有限个物品拆成有限个不同的物品。然后就转化成了01背包。

    //a[i]是拆开后第i件物品本来的序号
    int cnt = 0;
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= num[i]; j++){
            a[++cnt] = i;
        }

优化

考虑二进制拆分

分组背包

有N件物品和一个容量为V的背包。第i件物品的价格(即体积,下同)是w[i],价值是c[i]。这N个物品分成了若干个组,每个组里面的商品不可以同时选择。
求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

原文地址:https://www.cnblogs.com/FoxC/p/11279841.html

时间: 2024-10-28 15:26:56

背包整理(01背包,完全背包,多重背包,分组背包)(待更新)的相关文章

背包(01,完全,多重,分组)

01背包 #include <cstdio> #include <iostream> using namespace std; int main() { int m,n,dp[100005]; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { int w,p; scanf("%d%d",&w,&p); for(int j=m;j>=w;j--) { dp[j]

hdu3535---AreYouBusy(混合分组背包,有坑点)

混合的分组背包,如果任意取,就是01背包 如果至多取一个,就是普通的分组背包 如果至少一个,就要考虑第一次和非第一次拿,注意由于体积可以为0,所以先得考虑非第一次拿的,不然某组的同一个物品会被计算2次 /************************************************************************* > File Name: hdu3535.cpp > Author: ALex > Mail: [email protected] >

hdu 1561 树形dp+分组背包

题意:就是给定n个点,每个地点有value[i]的宝物,而且有的宝物必须是另一个宝物取了才能取,问取m个点可以获得的最多宝物价值. 一个子节点就可以返回m个状态,每个状态表示容量为j(j<=m)时选最多的宝物,而一个子节点中只可以选择一个状态进行转移,每个节点有若干个子节点,问题就转换为分组背包,几个子节点就是几个分组背包,体积是选几个地点,价值是宝物价值. 状态转移方程: dp[v][1] = Money[v]; (v为叶子节点)                    dp[v][j] = m

多重背包转换成完全背包和01背包

void CompletePack(int cost,int weight)   多重背包 { for(int i=cost;i<=m;i++) dp[i]=max(dp[i],dp[i-cost]+weight); } void ZeroOnePack(int cost,int weight)    01背包 { for(int i=m;i>=cost;i--) dp[i]=max(dp[i],dp[i-cost]+weight); } void MultiplyPack(int cost,

背包之01背包、完全背包、多重背包详解

首先说下动态规划,动态规划这东西就和递归一样,只能找局部关系,若想全部列出来,是很难的,比如汉诺塔.你可以说先把除最后一层的其他所有层都移动到2,再把最后一层移动到3,最后再把其余的从2移动到3,这是一个直观的关系,但是想列举出来是很难的,也许当层数n=3时还可以模拟下,再大一些就不可能了,所以,诸如递归,动态规划之类的,不能细想,只能找局部关系. 1.汉诺塔图片 (引至杭电课件:DP最关键的就是状态,在DP时用到的数组时,也就是存储的每个状态的最优值,也就是记忆化搜索) 要了解背包,首先得清楚

c++01背包一维数组版及java多重背包

#include<bits/stdc++.h> #define ll long long using namespace std; const int maxn=1010; int c[maxn],w[maxn]; int dp[maxn]; int main(){ int n,v; cin>>n>>v; for(int i=1;i<=n;i++) cin>>c[i]; for(int i=1;i<=n;i++) cin>>w[i];

01背包问题的学习(来源:背包九讲)

问题: 有N件物品和一个容量为V的背包.第i件物品的费用是c[i],价值是w[i].求解将哪些物品装入背包可使价值总和最大. 思路: 这是最基础的背包问题,特点是:每种物品仅有一件,可以选择放或不放.用子问题定义状态:即f[i][v]表示前i件物品恰放入一个容量为v的背包可以获得的最大价值.则其状态转移方程便是:f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]}.这个方程非常重要,基本上所有跟背包相关的问题的方程都是由它衍生出来的.所以有必要将它详细解释一下:"

HDU 3033 I love sneakers! (01背包+反分组背包)

题意:给你 n,m,k,表示有k种鞋子共n双,你有m的容量: 每双鞋子有容量p和价值v:问是否买全k种鞋子,若能在容量为m的情况下最多能买到鞋子的价值为多少: 每双鞋子只能买一次(01背包),每种鞋子至少买一种(分组背包:每组只能有一个)与传统分组背包的限制相反. 注意初始化!!! #include<cstdio> #include<stdlib.h> #include<string.h> #include<string> #include<map&g

HDU 3033 I love sneakers! 我爱运动鞋 (分组背包,01背包,严重变形)

题意:给出k家店,每家店内有各种价格的鞋子(同样的鞋子只能买一双),每双鞋子有价值,要求每家店至少买一双.给出m钱,求获得的最大价值. 思路:分组背包严重变形了,变成了相反的,每组物品至少挑1件(分组背包是至多挑1件).虽然是分组背包的变形,但是用到的却是01背包的思路.要求每家店至少买1双,那么可以只买一双双,也可以买多双.难点在这.需要维护两行dp状态值即可.第一行是前面组的物品的最佳状态,第二行是第i件物品之前的最佳状态(已经装进同组物品). 对于i组第t件物品,(1)要么从i组之前的状态