• Knapsack Problem


    背包九讲


    0-1 knapsack problem

    01背包-牛客网

    已知一个背包最多能容纳体积之和为V的物品,现有 n 个物品,第 i 个物品的体积为 vi , 重量为 wi,求当前背包最多能装多大重量的物品?

    使用动态规划来解决01背包问题:

    首先定义dp数组:dp[i][j] := 0-i号物品面对容量为j的背包所能获得的最大重量

    状态转移方程:

    d p [ i ] [ j ] = { d p [ i − 1 ] [ j ] , 容量不足,不放入物品 i m a x ( d p [ i − 1 ] [ j ] , d p [ i − 1 ] [ j − v [ i ] ] + w [ i ] ) , 考虑拿这件物品能否获得更大重量 dp[i][j]=

    {dp[i1][j],imax(dp[i1][j],dp[i1][jv[i]]+w[i])," role="presentation">{dp[i1][j],imax(dp[i1][j],dp[i1][jv[i]]+w[i]),
    dp[i][j]={dp[i1][j],容量不足,不放入物品imax(dp[i1][j],dp[i1][jv[i]]+w[i]),考虑拿这件物品能否获得更大重量

    class Solution {
    public:
        int knapsack(int V, int n, vector<vector<int> >& vw) {
            vector<vector<int>> dp(n + 1, vector<int>(V + 1, 0));
            for (int i = 1; i <= n; ++i) {
                for (int j = 1; j <= V; ++j) {
                    if (j < vw[i - 1][0]) {
                        dp[i][j] = dp[i - 1][j];
                    } else {
                        dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - vw[i - 1][0]] + vw[i - 1][1]);
                    }
                }
            }
            return dp[n][V];
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    由于dp问题具有无后效性,可以采用滚动数组的方式节省内存,此时状态转移方程化为:

    if j >= v[i]:
    	dp[j] = max(dp[j], dp[j - v[i]] + w[i]);
    
    • 1
    • 2

    Charm Bracelet:定义一维的dp数组,每次从后向前刷新dp数组:

    #include 
    #include 
    using namespace std;
    
    int main() {
        int N, M;
        cin >> N >> M;
        vector<int> W(N, 0);
        vector<int> D(N, 0);
        vector<int> dp(M + 1, 0);
        for (int i = 0; i < N; ++i) {
            cin >> W[i] >> D[i];
        }
        for (int i = 0; i < N; ++i) {
            for (int j = M; j >= 1; --j) {
                if (j >= W[i]) {
                    dp[j] = max(dp[j], dp[j - W[i]] + D[i]);
                }
            }
        }
        cout << dp[M] << endl;
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    full knapsack problem

    完全背包-牛客网

    你有一个背包,最多能容纳的体积是V。现在有n种物品,每种物品有任意多个,第 i 种物品的体积为vi,价值为wi,求这个背包至多能装多大价值的物品?

    完全背包的状态转移方程和01背包极其相似:

    d p [ i ] [ j ] = { d p [ i − 1 ] [ j ] , 容量不足,不放入物品 i m a x ( d p [ i − 1 ] [ j ] , d p [ i ] [ j − v [ i ] ] + w [ i ] ) , 考虑拿这件物品能否获得更大重量 dp[i][j]=

    {dp[i1][j],imax(dp[i1][j],dp[i][jv[i]]+w[i])," role="presentation">{dp[i1][j],imax(dp[i1][j],dp[i][jv[i]]+w[i]),
    dp[i][j]={dp[i1][j],容量不足,不放入物品imax(dp[i1][j],dp[i][jv[i]]+w[i]),考虑拿这件物品能否获得更大重量
    而且,考虑使用滚动数组压缩空间,完全背包和01背包的状态转移方程是一样的。区别在于dp数组的遍历方式:完全背包问题必须顺序推导dp数组,而01背包采用逆序推导dp数组

    if j >= v[i]:
    	dp[j] = max(dp[j], dp[j - v[i]] + w[i]);
    
    • 1
    • 2
    class Solution {
      public:
        vector<int> knapsack(int v, int n, vector<vector<int> >& nums) {
            // write code here
            vector<int> res;
            vector<int> dp(v + 1, 0);
            vector<int> pack(v + 1, -255);
            pack[0] = 0;
            for (int i = 0; i < n; ++i) {
                for (int j = 0; j <= v; ++j) {
                    if (j >= nums[i][0]){
                        dp[j] = max(dp[j], dp[j - nums[i][0]] + nums[i][1]);
                        pack[j] = max(pack[j], pack[j - nums[i][0]] + nums[i][1]);	//只考虑能从0一步步跳到v的w
                    }
                }
            }
            res.push_back(dp[v]);
            if (pack[v] > 0) {
                res.push_back(pack[v]);
            } else {
                res.push_back(0);
            }
            return res;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    Piggy-Bank


    fractional knapsack problem

    与上面的两种背包问题不同,分数背包问题(物品可以被任意分割)比较简单,可以用贪心算法解决:每次都选择单位价值最大的物品装入背包,如果未满,则选择下一个价值次大的物品装入背包

    圣诞老人的礼物-百练

    #include 
    #include 
    #include 
    using namespace std;
    
    #define MAXN (100+10)
    
    struct Box {
    	int v;
    	int w;
    	double density;
    	Box() {}
    	Box(int vv, int ww) :v(vv), w(ww), density(double(v) / w) {}
    	bool operator<(const Box& b) {
    		return density < b.density;
    	}
    };
    
    int n, weigth;
    double total_w = 0;
    double total_v = 0;
    Box boxes[MAXN];
    
    int main() {
    	cin >> n >> weigth;
    	int v, w;
    	for (int i = 0; i < n; ++i) {
    		cin >> v >> w;
    		boxes[i] = Box(v, w);
    	}
    	sort(boxes, boxes + n);
    	for (int i = n - 1; i >= 0; --i) {
    		if (total_w + boxes[i].w < weigth) {
    			total_w += boxes[i].w;
    			total_v += boxes[i].v;
    		}
    		else {
    			total_v += boxes[i].density * (weigth - total_w);
    			total_w = weigth;
    		}
    	}
    	printf("%.1f\n", total_v);
    	return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
  • 相关阅读:
    养老保险不到60岁能领吗
    用例图包含关系、扩展关系、泛化关系解析(最全总结,非常详细)
    电源modbus 485 测试方法之功能选择
    “两客一危”车辆综合监控信息化产品及应用分析
    12 【react高级指引(上)】
    点云处理简介
    【做题笔记】多项式/FFT/NTT
    【目标检测】36、OTA: Optimal Transport Assignment for Object Detection
    ArrayList快速失败机制源码及特殊失效场景分析
    【iOS开发- KVO(键值监听)】
  • 原文地址:https://blog.csdn.net/DanielSYC/article/details/127566537