链接:https://ac.nowcoder.com/acm/contest/24213/1017
来源:牛客网
来源:牛客网
题目描述
有一个箱子容量为V(正整数,0 ≤ V ≤ 20000),同时有n个物品(0<n ≤ 30),每个物品有一个体积(正整数)。
要求n个物品中,任取若干个装入箱内,使箱子的剩余空间为最小。
要求n个物品中,任取若干个装入箱内,使箱子的剩余空间为最小。
输入描述:
1个整数,表示箱子容量 1个整数,表示有n个物品 接下来n行,分别表示这n个物品的各自体积
输出描述:
1个整数,表示箱子剩余空间。
题型:
动态规划--求最大值+选或不选问题
思路:
1.明确总问题:求最小剩余空间-->求总体积-最大体积-->需要求出不超过总体积的最大体积
2.明确子问题:求当已经选择了i个物品时,总体积为j
3.明确dp含义:可以设dp[i][j]为选择了i个物品时,总体积为j的状态是否存在,如果存在,则为1,如果不存在,则为0,所以不超过总体积的最大体积的值即为i从V开始,一直到0,dp[n][i]最先为1时的i的值
4.明确状态转移方程:当j<a[i]时,有dp[i][j]=dp[i-1][j],当j>=a[i]时,有dp[i][j]=dp[i-1][j]||dp[i-1][j-a[i]];
5.明确初始化:dp[0][0]=1,表示什么都不选时体积为0的状态是存在的
6.明确i和j的范围:i:1~n j:0~V(注意j不是1~V,j=0也要考虑)
代码(二维数组):
#include<bits/stdc++.h> using namespace std; int dp[32][20200],a[32]; int main(){ int n,V,maxn=0; scanf("%d%d",&V,&n); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); } dp[0][0]=1; for(int i=1;i<=n;i++){ for(int j=0;j<=V;j++){ if(j<a[i]) 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]){ maxn=i; break; } } printf("%d\n",V-maxn); return 0; }
当然,这个二维数组可以压缩成一维(因为第i行的状态只跟第i-1行的状态有关),注意压缩之后j要反着取,并且j的范围改成V~a[i](因为a[i]前的状态不需要改,直接继承之前的状态就行了)
代码(一维数组):
#include<bits/stdc++.h> using namespace std; int dp[20200],a[32]; int main(){ int n,V,maxn=0; scanf("%d%d",&V,&n); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); } dp[0]=1; for(int i=1;i<=n;i++){ for(int j=V;j>=a[i];j--){ dp[j]=dp[j]||dp[j-a[i]]; } } for(int i=V;i>=0;i--){ if(dp[i]){ maxn=i; break; } } printf("%d\n",V-maxn); return 0; }