`
从此醉
  • 浏览: 1044827 次
  • 性别: Icon_minigender_1
  • 来自: US
社区版块
存档分类
最新评论

简单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));
	}
}


分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics