• 背包整理(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])(倒序枚举) ]

    因此处理一件01背包中的物品的过程为

        for(int v = V; v >= w[i]; v--){
            d[v] = max(d[v],d[v - w[i]] + c[i]);
        }
    

    01背包的两种初始化

    当题目要求背包被装满时,初始化时应使(d[0]=0, d[1...V] = -infty)
    因为当背包内没有放入物品时(d[1...V])不可能被装满,是不合法的情况。
    当题目没有要求背包恰好被装满时,初始化时应使(d[0...V] = 0)

    完全背包

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

    用d[i][v]表示前i种背包装入容量为v的背包中所可以获得的最大价值
    对于一种物品,只有两种情况
      情况一: 第i件不放进去,这时所得价值为:$$d[i-1][v]$$
      情况二: 第i件放进去,这时,我们需要枚举放进去多少件,设为K,所得价值为:

    [d[i-1][v-K*c[i]]+K*w[i] ]

    状态转移方程为:(max limits_{0<=K<=v/w[i]} d[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次) ]

    可以感性理解一下
    因此处理一件完全背包中的物品的过程为

        for(int v = w[i]; v <= V; v++){
            d[v] = max(d[v],d[v - w[i]] + c[i]);
        }
    

    多重背包

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

    对于一种物品,只有两种情况
      情况一: 第i件不放进去,这时所得价值为:$$d[i-1][v]$$
      情况二: 第i件放进去,这时,我们需要枚举放进去多少件,设为K,所得价值为:$$d[i-1][v-Kw[i]]+Kc[i]$$
    状态转移方程为:$$d[i][v] = max limits_{0<=K<=v/w[i],K<= n[i]}(f[i-1][v-Kw[i]]+Kc[i])$$

    二进制拆分优化

    显然用(2^0,2^1,2^2....2^{k-1})可以表示(1)(2^k -1)中任意一个数。
    我们把n[i]拆成将第i种物品分成若干件物品,其中每件物品有一个系数,这件物品的费用和价值均是原来的费用和价值乘以这个系数。使这些系数分别为(2^0,2^1,2^2....n[i] - (2^k - 1))。这样对于0...n[i]中的每个整数,都可以用若干系数的和表示。

    for(int i = 1; i <= n; i++){
    	int num = min(n[i],V/w[i]);
    	for(int k = 1; num > 0; k <<= 1){
    		if(k > num) k = num;
    		num -= k;
    		for(int v = V; v >= w[i]*k; v--)
    			d[v] = max(d[v],d[v - w[i] * k] + c[i] * k);
    	}
    }
    

    分组背包

    有N件物品和一个容量为V的背包。第i件物品的价格(即体积,下同)是w[i],价值是c[i]。这N个物品分成了若干个组,每个组里面的商品不可以同时选择。
    求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
    对于每一组物品有两种决策
    1.不选
    2.选择其中一个物品
    状态转移方程$$d[k][v]=max(dp[k-1][v],dp[k-1][v-w[i]]+c[i]) (i属于第k组)$$
    显然对于每一组物品我们只做一次决策。
    转化成一维$$d[v]=max(dp[v],dp[v-w[i]]+c[i])$$

    for (所有的组k)
        for (int j = V; j >= 0; j--)
            for (所有属于组k的i)
                f[j] = max{f[j], f[j - w[i]] + v[i]}
    
  • 相关阅读:
    入门经典 第七章 7.3.3 二进制生成子集
    gdb调试方法简要总结
    Erlang_1
    hdu 1144
    创建一个类,重载运算符实现多项式的加,减,乘运算
    ubuntu12.04 iNodeClient 连校园网
    ftime使用
    CodeForce 264 A. Escape from Stones
    hdu 1161 Eddy's mistakes
    hdu 1064
  • 原文地址:https://www.cnblogs.com/FoxC/p/11279841.html
Copyright © 2020-2023  润新知