题意
- n个物品,箱子体积为v,装入物品后,箱子的最小剩余体积是多少
思路
-
动态规划
-
对于每一个物品,考虑放或者不不放,观察体积
-
即维护放入前i个物品能否满足体积为j
-
(当前物品已经比需要的体积大了,放不进去)
-
(当前物品可以放的进去,考虑放/不放)
-
特别的,本题有三种写法:正常dp,01滚动,就地滚动
-
因为每一行的值之和上一行有关,且我们只在乎最后一行的值,每次更新的时候只用看前一行,所以只用两行来存,一行是当前行,一行是上一行,把原来的行号变成mod2意义下的行号即可(01滚动)
-
由于上一行有的值下一行一定也满足,所以我们可以直接在原有行的基础上改动(就地滚动)
-
注意:如果就地滚动的话要从没维护的开始,到体积无法容纳当前物体为止,避免一个物品被重复维护
Eg.当前物品体积为三,如果从头开始滚动,到j=3时,dp[3]=dp[0],到j=6时,dp[6]=dp[3]……造成错误
AC代码
#include <bits/stdc++.h>
using namespace std;
int dp[505050];
int main(){
int v,n;
cin >> v >> n ;
int a[50] = {0};
for(int i=1;i<=n;i++) cin >> a[i];
//v1:正常dp
// dp[0][0]=1;
// for(int i=1;i<=n;i++){
// for(int j=0;j<=v;j++){
// if(a[i]>j) dp[i][j]=dp[i-1][j];
// else dp[i][j] = dp[i-1][j] || dp[i-1][j-a[i]];
// }
// }
// for(int i=v;i>=0;i--){
// if(dp[n][i]){
// cout << v-i <<endl;
// break;
// }
// }
//v2:01滚动,压缩到两行内
// dp[0][0]=1;
// for(int i=1;i<=n;i++){
// for(int j=0;j<=v;j++){
// if(a[i]>j) dp[i%2][j]=dp[(i-1)%2][j];
// else dp[i%2][j] = dp[(i-1)%2][j] || dp[(i-1)%2][j-a[i]];
// }
// }
// for(int i=v;i>=0;i--){
// if(dp[n%2][i]){
// cout << v-i <<endl;
// break;
// }
// }
//v3:就地滚动,只占用一行
dp[0]=1;
for(int i=1;i<=n;i++){
for(int j=v;j>=a[i];j--){
if(dp[j-a[i]]) dp[j] = dp[j-a[i]];
}
}
for(int i=v;i>=0;i--){
if(dp[i]){
cout << v-i <<endl;
break;
}
}
return 0;
}