前一段时间我学习了一下动态规划里面的01背包和完全背包,自己做了一些总结与大家分享一下,希望对你们有帮助
首先来说一下什么是动态规划
动态规划就是把大问题拆分成小问题,通过寻找大问题与小问题的递推关系,解决一个个小问题,最终达到解决原问题的效果。通过填写表把所有已经解决的子问题答案纪录下来,动态规划解决问题的核心就在于填表,表填写完毕,最优解也就找到。
0-1背包
问题描述:有N件物品和一个容量为V的背包。第i件物品的价值是v[i],重量是w[i]。求解将哪些物品装入背包可使价值总和最大。//具体问题:物品个数n=5,物品重量w[n+1]={0,2,2,6,5,4},物品价值V[n+1]={0,6,3,5,4,6},背包的最大容量为10,
总体思路:求K问题的最优解,就要先求出K-1问题的最优解,以此类推,最后就转化为求1问题的最优解,然后再往前推,那么K问题的最优解就求出来了。总而言之,就是把每种状态都求出来。
具体实现步骤:我画了一个表来帮助大家理解
然后将每种状态都算出来,最后将表填完之后就是下面的结果。
最后数据date[ N ][ M ]就是这个问题的答案了。
代码实现如下:
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <algorithm>
using namespace std;
#define N 5
#define M 10
int date[N+1][M+1],w[N+1]={0,2,2,6,5,4},v[N+1]={0,6,3,5,4,6};
void DP()
{
for (int i=1;i<=N;i++)
{
for (int j=1;j<=M;j++)
{
if (j>=w[i])
date[i][j]=max(date[i-1][j],date[i-1][j-w[i]]+v[i]);
else
date[i][j]=date[i-1][j];
printf("%4d",date[i][j]);
}
printf("\n");
}
}
int main()
{
memset(date,0,sizeof(date));
DP();
printf("%d\n",date[N][M]);
return 0;
}
然后就是这个代码可以进行改进,就是将存储数据的二维数组更改为一维的。关键性代码更改如下:
for (i=1;i<=N;i++)
for (j=M;j>=1;j--)
date[j]=max(date[j],date[j-w[i]]+v[i]);
完全背包
问题描述:有一个容积为V的背包,同时有n种物品,每种物品均有无数多个,并且每种物品的都有自己的体积和价值。求使用该背包最多能够装的物品价值总和。// 具体问题: 物品种数N=4,物品重量w[N+1]={0,2,3,4,7},物品价值V[N+1]={0,1,3,5,9},背包的最大容量为10.
总体思路:思路跟01背包差不多,分解问题,求分解问题的最优解,因为完全背包里面,每种物品是无限多的,所以每次更新数据的时候还是对这种物品进行装拿。
具体实现步骤:在这里我还是采用打表来帮助理解
更新每一种状态后
最后数据date[ N ][ M ]就是这个问题的答案了。
代码实现如下:
#include <stdio.h>
#include <iostream>
#include <string.h>
using namespace std;
#define N 4
#define M 10
int date[N+1][M+1],w[N+1]={0,2,3,4,7},v[N+1]={0,1,3,5,9};
void DP()
{
int i,j;
for (i=1;i<=N;i++)
{
for (j=1;j<=M;j++)
{
if (j>=w[i])
date[i][j]=max(date[i-1][j],date[i][j-w[i]]+v[i]);
else
date[i][j]=date[i-1][j];
printf("%4d",date[i][j]);
}
printf("\n");
}
}
int main()
{
memset(date,0,sizeof(date));
DP();
printf("%d\n",date[N][M]);
return 0;
}
同样的,这个代码也可以进行改进,代码更改如下:
for (i=1;i<=N;i++)
for (j=w[i];j<=M;j++)
date[j]=max(date[j],date[j-w[i]]+v[i]);
我这里只说明了这一种方法,如果你有其他方法,欢迎分享。