问题描述
有一个箱子容量为V(正整数,0<=V<=20000),同时有n个物品(0<n<=30),每个物品有一个体积(正整数)。
要求n个物品中,任取若干个装入箱内,使箱子的剩余空间为最小。
输入格式
第一行为一个整数,表示箱子容量;
第二行为一个整数,表示有n个物品;
接下来n行,每行一个整数表示这n个物品的各自体积。
输出格式
一个整数,表示箱子剩余空间。
例子
样例输入
24
6
8
3
12
7
9
7
样例输出
0
思路
可设一个元素个数为 max(v)+1的数组dp[20001],里面任意一个元素dp[i]表示箱子容积为 i 时可放入的物品的体积。因为物品的体积并不是单位体积,因此dp[i]并不一定等于 i,例如有3个物体,体积分别为3,4,5,那么容积为3和4的箱子可放入的物品的体积均为3,即dp[3] = dp[4] = 3。对于每一个物体,都有两种选择-放入或者不放入,所以外层循环可对每个物品进行遍历,而每选择一个物品,定会对大于该物品体积的dp数组元素产生影响,从而还需要一个内层数组对大于该物品体积的dp数组元素进行遍历更新。更新方法为:dp[i] = max{ dp[i] , dp[i - vi]+vi },其中vi为当前物品的体积,max中的dp[i]表示不放入该物体时的解, dp[i - vi]+vi表示放入该物体时的解(i-vi表示给即将放入的物品留出合适的体积,如之前的例子,dp[i-vi]并不一定等于dp[i] - vi),取最大值,即为最优解。需要注意的是,需要先将dp数组中的每一个元素初始化为0。
#include <stdio.h>
int V;//箱子体积
int n;//个数
int a[31]; //存放物品的体积
int dp[20001]={0}; //dp[i]表示箱子容积为i时可放入的物品的体积 ,注意要初始化为0
int main ()
{
int i,j;
int t;
scanf("%d",&V);
scanf("%d",&n);
for(i=0;i<n;i++)
scanf("%d",&a[i]);
for(i=0;i<n;i++)//外循环,遍历每个箱子
{
for(j=V;j>=a[i];j--)//内循环,遍历每个容积
{
if(dp[j]>( dp[j-a[i]]+a[i] ))
dp[j]=dp[j];
else
dp[j]=dp[j-a[i]]+a[i]; //取最大值,最优解
}
}
printf("%d",V-dp[V]); //输出最小的容积
return 0;
}
运行示例