简单背包问题(子集和)

问题如下:

设有一个背包可以放入的物品重量为S,现有n件物品,重量分别是w1,w2,w3,…wn。 
问能否从这n件物品中选择若干件放入背包中,使得放入的重量之和正好为S。 
如果有满足条件的选择,则此背包有解,否则此背包问题无解。(可以理解为一个集合中否存在一个子集使子集和为一定值C)
  
Input输入数据有多行,包括放入的物品重量为s,物品的件数n,以及每件物品的重量(输入数据均为正整数)
多组测试数据。 
Output对于每个测试实例,若满足条件则输出“YES”,若不满足则输出“NO“ 
Sample Input
20 5
1 3 5 7 9
Sample Output
YES

 

0- 1 背包问题如果采用递归算法来描述则非常清楚明白, 它的算法根本思想是假设用布尔函数
knap( s, n) 表示n 件物品放入可容质量为s 的背包中是否有解( 当knap 函数的值为真时

说明问题有解,其值为假时无解) . 我们可以通过输入s 和n 的值, 根据它们的值可分为以下几种情况讨论:

( 1) 当s= 0时可知问题有解, 即函数knap( s, n) 的值为true; ( 2) 当s< 0 时这时不可能,

所以函数值为false; ( 3) 当输入的s> 0 且n< 1 时即总物品的件数不足1, 这时函数值为false,

只有s> 0 且n \1 时才符合实际情况,这时又分为两种情况: ( 1) 选择的一组物体中不包括Wn

则knap( s, n) 的解就是knap( s, n- 1) 的解. ( 2) 选择的一组物体中包括Wn 则knap( s, n) 的解

就是knap( s- Wn, n- 1) 的解. 这样一组Wn 的值就是问题的最佳解. 这样就将规模为n 的问题转化为

规模为n- 1 的问题. 综上所述0- 1 背包问题的递归函数定义为:
knap( s, n) =∕true, s= 0
             ︳false, s< 0
             ︳false, s> 0 且n< 1
              \knap( s, n- 1) 或knap( s- Wn, n- 1) , s> 0 且n>= 1

import java.util.*;

public class Bag {

/**
* @param args
*/

public static boolean knap(int weight, int num) {
if (weight == 0)
return true;
if (weight < 0 || (weight > 0 && num == 0))
return false;

if (knap(weight - date[num - 1], num - 1)) // 拾取date[num-1]物品
{
queue.add(date[num - 1]);
return true;
}

return knap(weight, num - 1);
}

static int[] date = { 1, 2, 3, 4, 5, 6 };
static int count = 0;

static Queue<Integer> queue = new LinkedList<Integer>();

public static void main(String[] args) {

System.out.println(Bag.knap(9, date.length));// 最大重量容量为9,最多有6件物品。

while (!queue.isEmpty())
System.out.println(queue.poll());

}

}

posted @ 2015-05-17 17:55  逍的遥  阅读(2208)  评论(0编辑  收藏  举报