ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

完全背包问题的几种求解方法

2022-07-02 12:01:55  阅读:139  来源: 互联网

标签:背包 求解 int max wi 几种 vi 物品


C++

完全背包问题

/*
 * 完全背包问题
 * 问题描述:
 *      有 N 种物品和一个容量是 V 的背包,每种物品都有无限件可用。
 *      第 i 种物品的体积是 vi,价值是 wi。
 *      求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
 *      输出最大价值。
 * 
 * 数据范围:  
 *      0 < N, V ≤ 1000
 *      0 < vi, wi ≤ 1000
 * 背包问题都是算法的经典题目,下面给出 完全背包 问题的解题思路:
 *
 * 解题思路1:
 *    数组定义:
 *      f[i][j] 表示前 i 个物品,体积为 j 的最大价值
 *    递归方程:
 *      f[i][j] = max(f[i-1][j], f[i-1][j-vi]+wi, f[i-1][j-2vi]+2wi, f[i-1][j-3vi]+3wi, ..., f[i-1][j-kvi]+kwi k=j//vi)
 *                max(f[i-1][j], f[i][j-vi]+wi)
 *    初始化结果:
 *      memset(f, 0xcf, sizeof f);
 *      f[0][0] = 0
 *    最终结果
 *      max(f[n][0], f[n][1], ..., f[n][m])
 *    复杂度分析:
 *      时间复杂度为 O(NM)
 *    tips:
 *      可以使用滚动数组,或者是变换内部循环顺序,将空间复杂度优化到 O(M)
 *      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]);
 *          }
 *      }
 *
 * 解题思路2:
 *    数组定义:
 *      f[i][j] 表示前 i 个物品,体积小于等于为 j 的最大价值
 *    递归方程:
 *      f[i][j] = max(f[i-1][j], f[i-1][j-vi]+wi, f[i-1][j-2vi]+2wi, f[i-1][j-3vi]+3wi, ..., f[i-1][j-kvi]+kwi k=j//vi)
 *                max(f[i-1][j], f[i][j-vi]+wi)
 *    初始化结果:
 *      memset(f, 0, sizeof f);
 *    最终结果
 *      f[n][m]
 *    复杂度分析:
 *      时间复杂度为 O(NM)
 *    tips:
 *      可以使用滚动数组,或者是变换内部循环顺序,将空间复杂度优化到 O(M)
 *      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]);
 *          }
 *      }
 *
 * 解题思路3:
 *    数组定义:
 *      f[i][j] 表示前 i 个物品,价值等于 j 的最小体积
 *    递归方程:
 *      f[i][j] = min(f[i-1][j], f[i-1][j-wi]+vi, f[i-1][j-2wi]+2vi, f[i-1][j-3wi]+3vi, ..., f[i-1][j-kwi]+kvi k=j//vi)
 *              = min(f[i-1][j], f[i][j-wi]+vi)
 *    初始化结果:
 *      memset(f, 0x3f, sizeof f);      INF
 *      f[0][0] = 0
 *    最终结果
 *      便利f[n][0-W] W 为最大的可能价值,找到满足 体积 m 的价值。
 *    复杂度分析:
 *      时间复杂度为 O(NW),本题而言 W 过高
 *    tips:
 *      可以使用滚动数组,或者是变换内部循环顺序,将空间复杂度优化到 O(M)
 *
 * 解题思路4:
 *    数组定义:
 *      f[i][j] 表示前 i 个物品,价值大于等于 j 的最小体积   
 *      这个需要注意状态为 负数的时候,是合法的。
 */
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 1010, M = N;
const int INF = 0x3f3f3f3f, _INF = 0xcfcfcfcf;
int n, m;
int f[N][M];
int v[N], w[N];


int solution_one() {
    memset(f, 0xcf, sizeof f);
    f[0][0] = 0;

    for (int i = 1; i <= n; i ++ ) {
        for (int j = 0; j <= m; j ++ ) {
            if (j >= v[i]) {
                f[i][j] = max(f[i - 1][j], f[i][j - v[i]] + w[i]);
            } else {
                f[i][j] = f[i - 1][j];
            }
        }
    }

    int res = _INF;
    for (int i = 0; i <= m; i ++ ) {
        res = max(res, f[n][i]);
    }
    return res;
}

int solution_two() {
    memset(f, 0, sizeof f);

    for (int i = 1; i <= n; i ++ ) {
        for (int j = 0; j <= m; j ++ ) {
            if (j >= v[i]) {
                f[i][j] = max(f[i - 1][j], f[i][j - v[i]] + w[i]);
            } else {
                f[i][j] = f[i - 1][j];
            }
        }
    }

    int res = f[n][m];
    return res;
}

int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i ++ ) {
        scanf("%d%d", &v[i], &w[i]);
    }

    int res = solution_one();

    printf("%d\n", res);
    return 0;
}




标签:背包,求解,int,max,wi,几种,vi,物品
来源: https://www.cnblogs.com/lucky-light/p/16436982.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有