背包模型

01背包:从右往左(因为只能由上一个物品的状态退出,如果从左往右则前边的保存的已是装了这件物品的值)递推,放不放此物品

完全背包:从左往右递推

多重背包:二进制拆包,或用单调队列优化(应该不考吧看的不明白QAQ)

装满背包:只把f[0]设为0

分组背包:把有依赖关系的方程一组,然后在一个阶段了分别dp不取附件,取一个,取两个(只有主次依赖)

二维费用:再加一维费用的循环

混合背包模板

#include<iostream>
#include<cstdio>
#include<algorithm>
#define maxn 205
using namespace std;
int n,m,w[maxn],v[maxn],a[maxn],dp[200005];
int main(){
    cin>>n>>m;
    int tw,tv,ta;
    for(int i = 1;i <= n;i++){
        scanf("%d%d%d",&tw,&tv,&ta);
        if(tw > m) n--;
        else{
            w[i] = tw;
            v[i] = tv;
            a[i] = ta;
        }
    }
    for(int i = 1;i <= n;i++){
        if(a[i] == -1){
            for(int j = w[i];j <= m;j++){
                dp[j] = max(dp[j],dp[j-w[i]]+v[i]);
            }
        }
        if(a[i] == 1){
            for(int j = m;j >= w[i];j--){
                dp[j] = max(dp[j],dp[j-w[i]]+v[i]);
            }
        }
        if(a[i] >  1){
            if(a[i] * w[i] >= m){
                for(int j = w[i];j <= m;j++){
                    dp[j] = max(dp[j],dp[j-a[i]*w[i]]+a[i]*v[i]);
                }
                continue;
            }
            int k = 1;
            for(;k<a[i];){
                for(int j = m;j >= w[i]*k;j--){
                    dp[j] = max(dp[j],dp[j-w[i]*k]+v[i]*k);
                }
                a[i] -= k;
                k = k<<1;
            }
            for(int j = m;j >= w[i]*a[i];j--){
                dp[j] = max(dp[j],dp[j-w[i]*a[i]]+v[i]*a[i]);
            }
        }
    }
    cout<<dp[m]<<endl;
    return 0;
}

优先队列优化

#include<iostream>
#include<algorithm>
int n,m,dp[200005],w[205],v[205],a[205];
using namespace std;
//“多重背包”通用模板
const int MAX_V = 200005;
//v、n、w:当前所处理的这类物品的体积、个数、价值
//V:背包体积, MAX_V:背包的体积上限值
//f[i]:体积为i的背包装前几种物品,能达到的价值上限。
inline void pack(int f[], int V, int v, int n, int w)
{
  if (n == 0 || v == 0) return;
  if (n == 1) {               //01背包
    for (int i = V; i >= v; --i)
      if (f[i] < f[i - v] + w) f[i] = f[i - v] + w;
    return;
  }
  if (n * v >= V - v + 1 || n == -1) {   //完全背包(n >= V / v)
    for (int i = v; i <= V; ++i)
      if (f[i] < f[i - v] + w) f[i] = f[i - v] + w;
    return;
  }

  int va[MAX_V], vb[MAX_V];   //va/vb: 主/辅助队列
  for (int j = 0; j < v; ++j) {     //多重背包
    int *pb = va, *pe = va - 1;     //pb/pe分别指向队列首/末元素
    int *qb = vb, *qe = vb - 1;     //qb/qe分别指向辅助队列首/末元素
    for (int k = j, i = 0; k <= V; k += v, ++i) {
      if (pe  == pb + n) {       //若队列大小达到指定值,第一个元素X出队。
        if (*pb == *qb) ++qb;   //若辅助队列第一个元素等于X,该元素也出队。
        ++pb;
      }
      int tt = f[k] - i * w;
      *++pe = tt;                  //元素X进队
      //删除辅助队列所有小于X的元素,qb到qe单调递减,也可以用二分法
      while (qe >= qb && *qe < tt) --qe;
      *++qe = tt;              //元素X也存放入辅助队列
      f[k] = *qb + i * w;      //辅助队列首元素恒为指定队列所有元素的最大值
    }
  }
}

int main(){

    cin>>n>>m;
    for(int i = 1;i <= n;i++){
        cin>>w[i]>>v[i]>>a[i];
    }
    for(int i = 1;i <= n;i++){
        pack(dp,m,w[i],a[i],v[i]);
    }
    cout<<dp[m];
    return 0;
}
时间: 2024-12-17 17:38:10

背包模型的相关文章

HDU 1712 ACboy needs your help-dp-(分组背包模型)

题意:n门课程用m天来学习,每门课用不同的天数来学习会有不同的学分,求能得到的最大的学分 分析:第一次接触分组背包.分组背包的模型就是不同的物品有不同的花费和价值,求在规定花费内能得到的最大的价值,这前面跟以前的背包最大的不同是物品分为几组,每组内的物品最多只能选一种:dp[i][j]表示前i组花费j能得到的最大的价值,不过实际在做的时候用一维数组就可以了 公式: for 组i for 花费j (从大到小) for 组内物品k if(j>=c[k]) dp[j]=max(dp[j],dp[j-c

动态规划--01背包模型

01背包剖析 问题引入 题目来源:ACwing:01背包问题 有 N 件物品和一个容量是 V 的背包.每件物品只能使用一次.第 i 件物品的体积是 vi,价值是 wi.求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大.输出最大价值. 输入格式 第一行两个整数,N,V,用空格隔开,分别表示物品数量和背包容积. 接下来有 N 行,每行两个整数 vi,wi,用空格隔开,分别表示第 i 件物品的体积和价值. 输出格式 输出一个整数,表示最大价值. 数据范围 0<N,V≤1000

[zoj3623]背包模型

给定n种物品,每种物品需要ti时间生产出来,生产出来以后,每单位时间可以创造wi个价值.如果需要创造至少W个价值,求最少时间. 思路:dp[j]表示用时间j所能创造的最大价值,则有转移方程:dp[j + t[i]] = max(dp[j + t[i], dp[j] + t * w[i]]).另外是否需要按一定顺序排序呢??以下是ac代码. 1 #pragma comment(linker, "/STACK:10240000,10240000") 2 3 #include <ios

金矿模型看动归(PASCAL版)

原文地址:http://www.cnblogs.com/SDJL/archive/2008/08/22/1274312.html{PASCAL语言} 对于动态规划,每个刚接触的人都需要一段时间来理解,特别是第一次接触的时候总是想不通为什么这种方法可行,这篇文章就是为了帮助大家理解动态规划,并通过讲解基本的01背包问题来引导读者如何去思考动态规划.本文力求通俗易懂,无异性,不让读者感到迷惑,引导读者去思考,所以如果你在阅读中发现有不通顺的地方,让你产生错误理解的地方,让你难得读懂的地方,请跟贴指出

通过金矿模型介绍动态规划

对于动态规划,每个刚接触的人都需要一段时间来理解,特别是第一次接触的时候总是想不通为什么这种方法可行,这篇文章就是为了帮助大家理解动态规划,并通过讲解基本的01背包问题来引导读者如何去思考动态规划.本文力求通俗易懂,无异性,不让读者感到迷惑,引导读者去思考,所以如果你在阅读中发现有不通顺的地方,让你产生错误理解的地方,让你难得读懂的地方,请跟贴指出,谢谢! ----第一节----初识动态规划-------- 经典的01背包问题是这样的: 有一个包和n个物品,包的容量为m,每个物品都有各自的体积和

codevs1959拔河比赛(二维费用背包)

1959 拔河比赛 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题目描述 Description 一个学校举行拔河比赛,所有的人被分成了两组,每个人必须(且只能够)在其中的一组,要求两个组的人数相差不能超过1,且两个组内的所有人体重加起来尽可能地接近. 输入描述 Input Description 数据的第1行是一个n,表示参加拔河比赛的总人数,n<=100,接下来的n行表示第1到第n个人的体重,每个人的体重都是整数(1<=weight<=450).

Codeforces Round #214 (Div. 2) C. Dima and Salad 背包

C. Dima and Salad Dima, Inna and Seryozha have gathered in a room. That's right, someone's got to go. To cheer Seryozha up and inspire him to have a walk, Inna decided to cook something. Dima and Seryozha have n fruits in the fridge. Each fruit has t

通过金矿模型介绍动态规划(转)

原文地址 点击下载01背包测试数据.rar 对于动态规划,每个刚接触的人都需要一段时间来理解,特别是第一次接触的时候总是想不通为什么这种方法可行,这篇文章就是为了帮助大家理解动态规划,并通过讲解基本的01背包问题来引导读者如何去思考动态规划.本文力求通俗易懂,无异性,不让读者感到迷惑,引导读者去思考,所以如果你在阅读中发现有不通顺的地方,让你产生错误理解的地方,让你难得读懂的地方,请跟贴指出,谢谢! ----第一节----初识动态规划-------- 经典的01背包问题是这样的: 有一个包和n个

通过金矿模型介绍动态规划(经典入门)

对于动态规划,每个刚接触的人都需要一段时间来理解,特别是第一次接触的时候总是想不通为什么这种方法可行,这篇文章就是为了帮助大家理解动态规划,并通过讲解基本的01背包问题来引导读者如何去思考动态规划.本文力求通俗易懂,无异性,不让读者感到迷惑,引导读者去思考,所以如果你在阅读中发现有不通顺的地方,让你产生错误理解的地方,让你难得读懂的地方,请跟贴指出,谢谢! ----第一节----初识动态规划-------- 经典的01背包问题是这样的: 有一个包和n个物品,包的容量为m,每个物品都有各自的体积和