早就想好好学下dp,因为之前一直对它很敬畏,虽然对我以后的工作应该没什么用,但是感觉dp已然成为我的
一个心病了,所以趁着现在,还算比较空吧,好好学习下算法。
其实到现在我也还是不怎么明白什么状态转移,以后只能靠多做几道题目来感受了,我就先把现在所想的记下来。
有n个物品,背包容量是m,每个物品对应重量wi,价值vi,求背包在容量内所能装的最大价值。
我第一个感觉就是穷举,每个背包都有两个选择,要或者不要,那么这样的算法复杂度就是2^n。
算法书上的解法是这样的(我现在还没想好怎么想到这一步):
开一个数组value[n][m],value(i,j)表示对是否选择第i个物品做决策,使在j重量下所能达到的最大value值。
那么建立的条件就是保证上一次value(i-1,j-wi)所取得的值也是最大的,这里只需要做n次决策,遍历m的范围,
因此算法复杂度为O(nm),得到
传说中的状态转移方程 value(i,j)=max{value[i-1][j],value[i-1][j-wi]+vi}j>=wi
for(i = 0; i <= m; i++)
value[0][i]=0;
for(i = 1; i <= n; i++)
{
cin>>w>>v;
for(j = 1; j <= m; j++)
{
if(j >= w)
value[i][j] = value[i-1][j]>value[i-1][j-w] + v ?
value[i-1][j] : value[i-1][j-w]+v;
else value[i][j] = value[i-1][j];
}
}
cout<<value[n][m]<<endl;
观察代码可知,此次的决策只与前一次有关,因此可以用滚动数组,从后往前推,这样保证了value[j]保存的是
上一次的value[j].
memset(value,0,sizeof(value));
for(i = 1; i <= n; i++)
{
cin>>w>>v;
for(j = m; j >= 0; j--)
{
if(j >= w)
value[j] = value[j] > value[j-w] + v?
value[j]:value[j-w] + v;
}
}
cout<<value[m]<<endl;