简单01背包问题求解 POJ:3628 Bookshelf 2

http://poj.org/problem?id=3628


Description

Farmer John recently bought another bookshelf for the cow library, but the shelf is getting filled up quite quickly, and now the only available space is at the top.

FJ hasNcows (1 ≤N≤ 20) each with some height ofHi(1 ≤Hi≤ 1,000,000 - these are very tall cows). The bookshelf has a height ofB(1 ≤BS, whereSis the sum of the heights of all cows).

To reach the top of the bookshelf, one or more of the cows can stand on top of each other in a stack, so that their total height is the sum of each of their individual heights. This total height must be no less than the height of the bookshelf in order for the cows to reach the top.

Since a taller stack of cows than necessary can be dangerous, your job is to find the set of cows that produces a stack of the smallest height possible such that the stack can reach the bookshelf. Your program should print the minimal 'excess' height between the optimal stack of cows and the bookshelf.

Input

* Line 1: Two space-separated integers:NandB
* Lines 2..N+1: Linei+1 contains a single integer:Hi

Output

* Line 1: A single integer representing the (non-negative) difference between the total height of the optimal set of cows and the height of the shelf.

Sample Input

5 16
3
1
3
5
6

Sample Output

1


 import java.io.BufferedReader;
 import java.io.InputStreamReader;
 import java.util.Arrays;

 public class Test3628 {

     static int n, b;
     static int[] h;
     static boolean[] used;
     static int min = Integer.MAX_VALUE;

     public static void main(String[] args) throws Exception {
         BufferedReader read = new BufferedReader(new InputStreamReader(
                 System.in));
         String[] s = read.readLine().split(" ");
         n = Integer.parseInt(s[0]);
         h = new int[n];
         used = new boolean[n];
         b = Integer.parseInt(s[1]);
         for (int i = 0; i < n; i++) {
             h[i] = Integer.parseInt(read.readLine());
         }
         Arrays.sort(h);
         search(0, 0);
         System.out.println(min);
     }

     public static boolean search(int sum, int deep) {
         if (sum >= b) {
             if (sum - b < min) {
                 min = sum - b;
             }
             return true;
         }
         for (int i = deep; i < n; i++) {
             if (used[i]) {
                 continue;
             }
             used[i] = true;
             if (search(sum + h[i], i + 1)) {
                 used[i] = false;
                 break;
             }
             used[i] = false;
         }
         return false;
     } 
}


总结:N较小,max较大时,应该用递归或dps求解。

N较大,MAX小时,用01背包求解。 或改进版的 fast版递归求解。


//关于各种方法的测试数据

public class Poj3628 {
	
	static int arr[] = {3,44,14,57,11,60,170,66,22,36,88,140,230,111,214,325,444,666,745,233};
	static int max = 894;
	static int n; //数组长度
	static int opt = -1; //最后的结果
	static int cnt = 0; //记录每个方法调用次数
	static int optArr[][]; //存储中间的最优结果
	static int packOpt[];
	
	static int M = 100; //循环测试次数
	/**
	 * dfs深度优先搜索做。
	 * @param sum 求得的中间结果
	 * @param index 当前的数组下标
	 */
	private static void dps(int sum, int index){
		//System.out.println(sum + " " +index);
		cnt ++;
		if(index == n){   //得到最终结果. 注意:这里应该是到n才结束
			if(sum > opt)
				opt = sum;
			return;
		}
		dps(sum, index + 1); //不使用index当前这个数
		if(sum + arr[index] <= max){ //如果index当前这个数可以用
			dps(sum + arr[index], index + 1);
		}
	}
	
	
	/**
	 * 由后向前递推
	 * @param remain 当前可用的容量
	 * @param index
	 * @return 在当前容量下  装index之前的数, 所能装下的最大值
	 */
	private static int fun(int remain, int index){
		cnt ++;
		if(index < 0)  //说明递推完毕。即 fun(remain,-1) = 0;则  fun(remain-arr[0],0) = arr[0];
			return 0;
		int a = fun(remain,index-1);
		if(remain - arr[index] >= 0){ //即当前这个数可用
			int b = fun(remain - arr[index],index-1) + arr[index];
			return Math.max(a, b);  //比较,得出较大的数
		}
		else   //不用当前这个数
			return a; 
		
	}
	
	private static int fastFun(int remain, int index){
		cnt ++;
		if(index < 0)
			return 0;
		if(optArr[remain][index] > 0)
			return optArr[remain][index];
		
		int a = fastFun(remain,index-1);
		if(remain - arr[index] >= 0){ //即当前这个数可用
			int b = fastFun(remain - arr[index],index-1) + arr[index];
			return (optArr[remain][index] = Math.max(a, b) );  //比较,得出较大的数
		}
		else   //不用当前这个数
			return (optArr[remain][index] = a); 
		
	}
	
	
	private static void pack01(){
		for(int i=0; i<n; i++){
			for(int j=max; j>=arr[i]; j--){
				cnt++;
				packOpt[j] = Math.max(packOpt[j-arr[i]] + arr[i], packOpt[j]);
			}
		}
	}
	
	
	public static void main(String[] args) {
		cnt = 0;
		n = arr.length;
		
		Long start = System.currentTimeMillis();
		
		for(int i=0; i<M; i++){
			dps(0,0);
		}
		Long end = System.currentTimeMillis();
		System.out.println("dps(0,0)调用次数:" + cnt);
		System.out.println(opt);
		System.out.println("时间:" + (end-start));
		
		cnt = 0;
		int result = 0;
		start = System.currentTimeMillis();
		for(int i=0; i<M; i++){
			result = fun(max,n-1);
		}
		end = System.currentTimeMillis();
		System.out.println("fun(max,n-1))调用次数:" + cnt);
		System.out.println(result);
		System.out.println("时间:" + (end-start));
		
		cnt = 0;
		start = System.currentTimeMillis();
		for(int i=0; i<M; i++){
			optArr = new int[max+1][n];
			result = fastFun(max,n-1);
		}
		end = System.currentTimeMillis();
		System.out.println("fastFun(max,n-1)):" + cnt);
		System.out.println(result);
		System.out.println("时间:" + (end-start));
		
		cnt = 0;
		start = System.currentTimeMillis();
		for(int i=0; i<M; i++){
			packOpt = new int[max+1];
			pack01();
		}
		end = System.currentTimeMillis();
		System.out.println(packOpt[max]);
		System.out.println("循环次数:" + cnt);
		System.out.println("时间:" + (end-start));
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值