问题描述:
有一个箱子容量为V(正整数,0<=V<=20000),同时有n个物品(0<n<=30),每个物品有一个体积(正整数)。要求n个物品中,任取若干个装入箱内,使箱子的剩余空间为最小。
输入格式
第一行为一个整数,表示箱子容量;
第二行为一个整数,表示有n个物品;
接下来n行,每行一个整数表示这n个物品的各自体积。
输出格式
一个整数,表示箱子剩余空间。
样例输入
24
6
8
3
12
7
9
7
样例输出
0
方法一:带剪枝的搜索法
public class _装箱问题 {
static int[] a,b;
static int max=Integer.MIN_VALUE,v;
public static void main(String[] args) {
Scanner reader=new Scanner(System.in);
v=reader.nextInt();
int n=reader.nextInt();
a=new int[n];
b=new int[n];
for(int i=0;i<n;i++)a[i]=reader.nextInt();
go(0,0);
System.out.println(v-max);
}
private static void go(int k,int sum) {
if(sum==v) {
System.out.println(0);//一旦找到为0的方案,可以终止程序
System.exit(0);
}
if(sum>v)return;
if(k>=a.length) {
max=Math.max(max, sum);
return;
}
go(k+1,sum);
go(k+1,sum+a[k]);
}
对于每一个物品,都有选或不选的两种可能,那么用函数分支,但是一定要提前剪枝,不然二分法的指数增长是很恐怖的(一张纸对折103次可以触及可观测宇宙的边界!)。所以当前值大于或等于容量时,都应该终止。
方法二:动态规划法
public static void main(String[] args) {//动态规划法
Scanner reader=new Scanner(System.in);
int v=reader.nextInt();
int n=reader.nextInt(),i,j;
int[] dp=new int[v+1];
int[] a=new int[n];
for(i=0;i<n;i++)a[i]=reader.nextInt();
for(i=0;i<n;i++) {
for(j=v;j>=a[i];j--) {
dp[j]=Math.max(dp[j], dp[j-a[i]]+a[i]);
}
}
System.out.println(v-dp[v]);
}
}
dp[i]代表容积为i的背包能装下的体积。