0/1背包
阿新 • • 發佈:2019-02-16
[] amp 價值 表示 容易 應該 分析 背包問題 註意
0/1背包的問題模型如下:
給定N個物品,其中第i個物品的體積為Vi ,價值為Wi 。有一容積為M的背包,要選擇一些物品放入背包,使物品體積不超過M的前提下,物品的價值總和最大。
dp[i][j]表示從前i個物品中選出了總體積為j的物品放入背包,物品的最大價值。即我們很容易得出解決的代碼:
memset(dp,0,sizeof(dp)); dp[0][0]=0; for(int i=1;i<=n;i++){ for(int j=0;j<=m;j++) dp[i][j]=dp[i-1][j]; for(intj=v[i];j<=m;j++) dp[i][j]=max(dp[i][j],dp[i-1][j-v[i]]+w[i]); }
根據上面的代碼 我們可以看出 狀態方程的推導只和當前狀態以及上一狀態有關。所以我們可以用滾動數組優化
memset(dp,0,sizeof(dp)); dp[0][0]=0; for(int i=1;i<=n;i++){ for(int j=0;j<=m;j++) dp[i&1][j]=dp[(i-1)&1][j];for(int j=v[i];j<=m;j++) dp[i&1][j]=max(dp[i&1][j],dp[(i-1)&1][j-v[i]]+w[i]); }
這裏我們只要2*m的空間即可
其實進一步分析代碼,在每個階段的開始,我們實際上只是執行了一次從dp[i-1][]到dp[i][]的一次拷貝,也就是說我們可以進一步省略掉dp數組的第一維
即dp[j]表示背包中放入總體積為j的最大價值
memset(dp,0,sizeof(dp)); dp[0]=0; for(int i=1;i<=n;i++){for(int j=m;j>=v[i];j--) dp[j]=max(dp[j],dp[j-v[i]]+w[i]); }
我們應該可以註意到,我們的第二重循環采用了倒序的方式,這是為了滿足0/1背包問題中每個物品是唯一的,只能放入一次的要求
0/1背包