动态规划问题笔记1-背包问题
最近刷题时碰到了动态规划的问题,最开始觉得很难,无从下手,研究了一下动态规划问题,觉得很神奇,做点儿笔记记录下。
结合具体的问题来理解比单独研究理论更形象一些。
问题:
要从物品重量为[2,3,5,5,10,2,8]的7个物体中选择几个物体放入容量为15的背包,恰好放满,总共有几种方案?
动态规划理论:
采用动态规划的方法来做这样的问题比较合适,动态规划采用空间换时间的策略,对于把大的问题换成小的问题,而小的问题中又相互关联的一类问题效果很好。本题中就有这样 的特征。
此处理论分析来自这里:https://www.cnblogs.com/variance/p/6909560.html
图片中abc三个公式详细解析:
a)式表示前个物品中挑选放入承重为0的背包中和没有物品放入承重为的背包中是相等为0。
b)式表明:如果第个物品的重量大于背包的容量,则装人前个物品得到的最大价值和装入前个物品得到的最大价值是相同的,即物品不能装入背包。
c)式表明:如果第个物品的重量小于背包的容量,则会有一下两种情况:
(1)如果把第个物品装入背包,则背包物品的价值等于第个物品装入容量位 的背包中的价值加上第个物品的价值;
(2)如果第个物品没有装入背包,则背包中物品价值就等于把前个物品装入容量为的背包中所取得的价值。
显然,取二者中价值最大的作为把前个物品装入容量为的背包中的最优解。
具体做法
生成一个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
输出:
上一篇: 【算法 二】—— 时间复杂度分析
下一篇: Java类型转换