动态规划问题笔记1-背包问题

最近刷题时碰到了动态规划的问题,最开始觉得很难,无从下手,研究了一下动态规划问题,觉得很神奇,做点儿笔记记录下。
结合具体的问题来理解比单独研究理论更形象一些。

问题:

要从物品重量为[2,3,5,5,10,2,8]的7个物体中选择几个物体放入容量为15的背包,恰好放满,总共有几种方案?

动态规划理论:

采用动态规划的方法来做这样的问题比较合适,动态规划采用空间换时间的策略,对于把大的问题换成小的问题,而小的问题中又相互关联的一类问题效果很好。本题中就有这样 的特征。
此处理论分析来自这里:https://www.cnblogs.com/variance/p/6909560.html
这里写图片描述
图片中abc三个公式详细解析:
a)式表示前 i 个物品中挑选放入承重为0的背包中和没有物品放入承重为 j 的背包中是相等为0。
b)式表明:如果第 i 个物品的重量大于背包的容量,则装人前 i 个物品得到的最大价值和装入前 i 1 个物品得到的最大价值是相同的,即物品 i 不能装入背包。
c)式表明:如果第 i 个物品的重量小于背包的容量,则会有一下两种情况:
(1)如果把第 i 个物品装入背包,则背包物品的价值等于第 i 1 个物品装入容量位 j W i 的背包中的价值加上第 i 个物品的价值 V i ;
(2)如果第 i 个物品没有装入背包,则背包中物品价值就等于把前 i 1 个物品装入容量为 j 的背包中所取得的价值。
显然,取二者中价值最大的作为把前 i 个物品装入容量为 j 的背包中的最优解。

具体做法

生成一个7行15+1列的二维数组由于存储大动态规划的结果;其中的列代表背包重量依次为0-15,每一行代表一个物品的重量。
对于每个物体,如果物体的重量大于背包的最大容积,则该物体不能装入背包,只能使用前面的物体来装填背包;
如果物体的重量小于背包的最大容积,比较该物体放入背包和为放入背包的最大价值值,取最大的;

#include<iostream>
#include<vector>

using namespace std;
#define SUM_MAX 1000
int dp[SUM_MAX][SUM_MAX];

template<typename T>
T max(const T& a, const T& b)
{
    if (a > b)return a;
    else return b;
}

int dpCal(int n, int sum, vector<int>& A)
{
    for (int i = 0; i <n; i++)
    {
        dp[i][0] = 1;//将物品i装入容量为0的背包的方法只有一种,即不放入物品,所以设置为1
    }
    for (int j = 1; j <= sum; j++)
    {
        dp[0][j] = 0;//将第一行的1-sum列设置为0
    }
    dp[0][A[0]] = 1;//将重量为A[0]的第一个物品放入容量为A[0]的背包只有一种方法,所以设置为1
    for (int i = 1; i <n; i++)//对第一个物品已经处理完毕,只需要从从第二个物品开始循环
    {
        for (int j = 0; j <= sum; j++)//对每个容量为j的背包进行处理
        {
            if (A[i]>j)
                dp[i][j] = dp[i - 1][j];//当物品i的重量大于背包的容量时,装不下该物品,装入之前的物品
            else
                //当物品i的重量小于背包的容量时,比较装入该物品时与不装入该物品时的价值大小(本题的每个物体价值可以认为是1),取最大的值。
                dp[i][j] = max<int>(dp[i - 1][j],dp[i - 1][j] + dp[i - 1][j - A[i]]);
        }
    }
    return dp[n-1][sum];
}

int main()
{
    int n, sum;
    cin >> n >> sum;
    if (sum > SUM_MAX)exit(1);
    vector<int> A(n, 0);
    for (int i = 0; i < n; i++)
    {
        cin >> A[i];
    }
    int method = 0;
    method = dpCal(n, sum, A);
    printf("动态规划表:\n");
    for (int i = 0; i <n; i++)
    {
        for (int j = 0; j <= sum; j++)
        {
            printf("%-4d", dp[i][j]);
        }
        printf("\n");
    }

    printf("\n可用的方法数:%3d\n",method);

    system("pause");
    return 0;
}

输入:
7 15
5 5 10 2 3 4 6
输出:
这里写图片描述

猜你喜欢

转载自blog.csdn.net/shuoyueqishilove/article/details/82346929