第一次接触动态规划,写一些自己的心得吧,动态规划真的还是挺难理解的,看了不少大牛的相关博客后才初步有所了解,哎,无奈自己智商捉急啊。下面是动态规划最简单的一种类型0-1背包问题。
问题:
有N件物品和一个容量为V的背包。第i件物品的体积是volume[i],价值是value[i]。求解将哪些物品装入背包可使这些物品的体积总和不超过背包容量,且价值总和最大。
思路:
对于每种物品来说,只有两种状态,装或者不装。于是我们就可以把它分解为子问题best[i][j],代表前i个物品放入体积为j的背包中所能达到的最大价值.这样我们就可以列出一个状态转移方程(注意:动态规划中列出状态转移方程是关键所在!呃。。。。至少大家都是这么说的。。。)那么该方程是什么呢?就像我之前所说的,对于第i件物品来说只有两种状态,装入背包或者不装。
列出如下状态转移方程:
best[i][j]=max{best[i-1][j],best[i-1][j-volume[i]]+value[i]},核心就是这个方程,如果第i件物品不装,最大价值就是best[i-1][j],如果装了,就得是不装第i件物品时的最大价值(此时的体积应该减去第i件物品的体积)加上第i件物品的价值。
定义边界值:
显而易见,若不边界,则该方程会无限递归下去。由于当物品为0或者空间为0时,最大价值一定是0,所以我们可以定义best[0][j]=0,best[i][0]=0,当然我们也可以直接先让该二维数组赋初值为0,之后再改动其中部分的值。
接下来就是码代码啦:
#include <iostream>
using namespace std;
int max(int a,int b)
{
int temp=b;
if (a>b)temp=a;
return temp;
}
int main()
{
int N,V;
int best[101][100]={0};
int i,j;
int value[100]={0},volume[100]={0};
cin>>N>>Vfor(i=1;i<=N;i++)cin>>value[i]>>volume[i];
for(i=0;i<=N;i++)
for(j=0;j<=V;j++)
best[i][j]=0;
for(i=1;i<=N;i++)
for(j=1;j<=V;j++)
{
if (j>=volume[i])best[i][j]=max(best[i-1][j],best[i-1][j-volume[i]]+value[i]);
else best[i][j]=best[i-1][j];
}
cout<<best[N][V]<<endl;
}
return 0;
}
虽然这样时间是优化到极限了,但空间还有优化的余地,所以自然而然还有一种是用一维数组来写,这需要状态转移方程的第二个循环反向遍历才行,这个会在下一章节加以介绍。(我也是研究了许久才明白。。。。说白了还是基础不扎实,刚接触算法的缘故。。。。)