题目描述
有一个箱子容量为V(正整数,0≤V≤20000),同时有n个物品(0<n≤30,每个物品有一个体积(正整数)。
要求n个物品中,任取若干个装入箱内,使箱子的剩余空间为最小。
输入格式
1个整数,表示箱子容量
1个整数,表示有n个物品
接下来n行,分别表示这n个物品的各自体积
输出格式
1个整数,表示箱子剩余空间。
输入输出样例
输入
24
6
8
3
12
7
9
7
输出
0
思路分析
其实就是背包问题。但是在做的时候想了个新思路。
令dp[i] = true
表示在 i 体积可以被若干个箱子凑出来。我们求箱子最小剩余空间就是找第一个 i 满足dp[i] = true.
对于每个箱子i,遍历所有体积j,如果dp[j] = true,表示这个体积之前被凑出来过,那么dp[j-a[i]]也为true.
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int main()
{
bool dp[20020];
int n, v;
scanf("%d",&v);
scanf("%d",&n);
int arr[50];
memset(dp,0,sizeof(dp));
dp[v] = 1;
for(int i = 0;i < n;i++) scanf("%d",&arr[i]);
for(int i = 0;i < n;i++)
{
for(int j = 0;j <= v;j++)
{
if(dp[j] && j-arr[i] >= 0) dp[j-arr[i]] = 1;
}
}
for(int i = 0;i <= v;i++)
{
if(dp[i])
{
printf("%d\n",i);
break;
}
}
return 0;
}
第二种就是正常的01背包问题.
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
//dp[i][j]表示前i物品,箱子容量为j时,箱子的最大价值(体积)
// dp[i][j] = max (dp[i-1][j], dp[i-1][j-a[i]]+a[i])
int main()
{
int v, n;
int dp[20020];
int arr[50];
memset(dp,0,sizeof(dp));
scanf("%d%d",&v,&n);
for(int i = 0;i < n;i++) scanf("%d",&arr[i]);
for(int i = 0;i < n;i++)
{
for(int j = v;j >= 0;j--)
{
if(j >= arr[i])
dp[j] = max(dp[j], dp[j-arr[i]]+arr[i]);
}
}
printf("%d\n",v-dp[v]);
return 0;
}