【算法设计与分析基础】8、背包问题

package cn.xf.algorithm.ch03;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.junit.Test;

/**
 * 
 * 功能:背包问题的穷举办法
 * @author xiaofeng
 * @date 2017年5月4日
 * @fileName NPHardProblem.java
 *
 */
public class NPHardProblem {

	/**
	 * 穷举
	 * @param capacity  背包容量
	 * @param worths	价值.
	 * @return
	 */
	public long backPack(int capacity, List<Long> worths) {
		 return 0l;
	}
	
	/**
	 * 网上办法
	 * @param set
	 * @param index
	 * @return
	 */
	public static ArrayList<ArrayList<Integer>> getSubsets(ArrayList<Integer> set, int index) {
		ArrayList<ArrayList<Integer>> allsubsets;
		if (set.size() == index) {
			allsubsets = new ArrayList<ArrayList<Integer>>();
			allsubsets.add(new ArrayList<Integer>()); // empty set
		} else {
			allsubsets = getSubsets(set, index + 1);
			int item = set.get(index);
			ArrayList<ArrayList<Integer>> moresubsets = new ArrayList<ArrayList<Integer>>();
			for (ArrayList<Integer> s : allsubsets) {
				ArrayList<Integer> newSubset = new ArrayList<Integer>();
				newSubset.addAll(s);
				newSubset.add(item);
				moresubsets.add(newSubset);
			}
			allsubsets.addAll(moresubsets);
		}
		return allsubsets;
	}
	
	/**
	 * 网络上的办法
	 * @param set
	 * @return
	 */
	public static ArrayList<ArrayList<Integer>> getSubsets2(ArrayList<Integer> set) {
		ArrayList<ArrayList<Integer>> allsubsets = new ArrayList<ArrayList<Integer>>();
		int max = 1 << set.size(); // how many sub sets
		for (int i = 0; i < max; i++) {
			int index = 0;
			int k = i;
			ArrayList<Integer> s = new ArrayList<Integer>();
			while (k > 0) {
				if ((k & 1) > 0) {
					s.add(set.get(index));
				}
				k >>= 1;
				index++;
			}
			allsubsets.add(s);
		}
		return allsubsets;
	}
	
	/**
	 * 求一个数组的所有集合,递归,
	 * 递归终止条件:当前子集的个数达到参数要求
	 * @param n
	 * @param datas
	 * @param setNum
	 * @param resultSet
	 */
	public void subsetErr(List<Integer> datas, int index, List<Set<Integer>> resultSet){
		if(datas.size() == index){
			return;
		}
		//求当前设置子集的个数的全部
		Set<Integer> curSubset = new HashSet<Integer>();
		for(int i = 0; i < datas.size(); ++i){
			//遍历所有以index索引开头的子集
			if(i < index)
				continue;
			
			//获取当前子集合,重新加入一个新的
			curSubset.add(datas.get(i));
			resultSet.add(curSubset);
			Set<Integer> curSubset2 = new HashSet<Integer>();
			curSubset2.addAll(curSubset);
			curSubset = curSubset2; //替换为一个新的索引
		}
		subsetErr(datas, index + 1, resultSet);
	}
	
	/**
	 * 获取所有数据的子集
	 * @param datas
	 * @param index
	 * @param curSubset
	 * @return
	 */
	public static List<List<Integer>> subset(List<Integer> datas, int index, List<Integer> curSubset) {
		List<List<Integer>> resultSet = new ArrayList<List<Integer>>();
		
		if(datas.size() == index){
//			resultSet.add(curSubset);
			return resultSet;
		}
		//循环递归所有的当前集合的下一个元素
		for(int i = index; i < datas.size(); ++i){
			List<Integer> curSubset2 = new ArrayList<Integer>();
			curSubset2.addAll(curSubset);
			//当前集合的最后有个元素
			int curLastEleIndex = -1;
			if(curSubset.size() > 0)
				curLastEleIndex = datas.indexOf(curSubset.get(curSubset.size() - 1));
			//当前集合的最后一个元素的序号不能比当前循环的数据的序号小
			if(i <= curLastEleIndex)
				continue;
			//入股是后面的元素,吧值添加进入集合
			curSubset2.add(datas.get(i));
			resultSet.add(curSubset2);
			//这个时候需要新建一个当前集合的复制对象进行拷贝
			//获取递归后续的集合
			resultSet.addAll(subset(datas, index + 1, curSubset2));
		}		
		return resultSet;
	}
	
	@Test
	public void npResult(){
		List<Integer> datas = new ArrayList<Integer>();
		datas.add(1);datas.add(2);datas.add(3);datas.add(4);
		List<Integer> zhongliang = new ArrayList<Integer>();
		zhongliang.add(7);zhongliang.add(3);zhongliang.add(4);zhongliang.add(5);
		List<Integer> jiazhi = new ArrayList<Integer>();
		jiazhi.add(42);jiazhi.add(12);jiazhi.add(40);jiazhi.add(25);
		//列出所有可能集
		int index = 0;
		List<List<Integer>> resultSet = new ArrayList<List<Integer>>();
		List<Integer> curSubset = new ArrayList<Integer>();
		NPHardProblem np = new NPHardProblem();
		resultSet = np.subset(datas, index, curSubset);
		
		//获取所有集合的总价值
		List<List<Integer>> resultOkSet = new ArrayList<List<Integer>>();
		List<Integer> allWorths = new ArrayList<Integer>();
		for(List<Integer> oneSet : resultSet){
			//获取子集总重量
			int allzl = 0;
			//价值
			int alljz = 0;
			for(int one : oneSet){
				allzl += zhongliang.get(one - 1);
				alljz += jiazhi.get(one - 1);
			}
			//重量不能超过背包10
			if(allzl <= 10){
				resultOkSet.add(oneSet);
				allWorths.add(alljz);
			}
		}
		//所有满足条件的子集选项
		for(List s : resultOkSet){
			System.out.println(s + " <====> " + allWorths.get(resultOkSet.indexOf(s)));
		}
//		System.out.println(resultOkSet);
	}
	
	@Test
	public void test0() {
		List<Integer> datas = new ArrayList<Integer>();
		datas.add(1);datas.add(2);datas.add(3);datas.add(4);datas.add(5);
		int index = 0;
		List<Set<Integer>> resultSet = new ArrayList<Set<Integer>>();
		List<Integer> curSubset = new ArrayList<Integer>();
		NPHardProblem np = new NPHardProblem();
		np.subsetErr(datas, index, resultSet);
		for(Set s : resultSet){
			System.out.println(s);
		}
	}
	
	
	@Test
	public void test1() {
		List<Integer> datas = new ArrayList<Integer>();
		datas.add(1);datas.add(2);datas.add(3);datas.add(4);
//		datas.add(4);datas.add(3);datas.add(2);datas.add(1);
		int index = 0;
		List<List<Integer>> resultSet = new ArrayList<List<Integer>>();
		List<Integer> curSubset = new ArrayList<Integer>();
		NPHardProblem np = new NPHardProblem();
		resultSet = np.subset(datas, index, curSubset);
		for(List s : resultSet){
			System.out.println(s);
		}
	}
	
	@Test
	public void test3() {
		ArrayList<Integer> datas = new ArrayList<Integer>();
		datas.add(1);datas.add(2);datas.add(3);datas.add(4);datas.add(4);
//		datas.add(4);datas.add(3);datas.add(2);datas.add(1);
		int index = 0;
		ArrayList<ArrayList<Integer>> resultSet = new ArrayList<ArrayList<Integer>>();
		List<Integer> curSubset = new ArrayList<Integer>();
		NPHardProblem np = new NPHardProblem();
		resultSet = np.getSubsets(datas, 0);
		for(List s : resultSet){
			System.out.println(s);
		}
	}
	
	/**
	 * 获取这个集合的所有子集的个数,不包括空集
	 * @param nums 单元个数
	 * @return
	 */
	public long getSubsetCount(int nums){
		int len = nums; //总个数
		long result = 0;	//个数和
		for(int i = 0; i < len; ++i) {
			int fenzi = 1; //分子
			int fenmu = 1; //当前分母
			for(int j = 0, k = 1; j < i; ++j) {
				fenzi *= (len - j);  //获取对应的伪阶乘,去掉j以下的数据
				for(; k <= j; ++k){
					fenmu *= (k + 1); //获取j的阶乘
				}
			}
			//获取对应的C41,C42,C43,C44=4 + 6 + 4 + 1
			result += fenzi / fenmu;
		}
		
		return result;
	}
	
	@Test
	public void test2(){
		NPHardProblem nphp = new NPHardProblem();
		System.out.println(nphp.getSubsetCount(4));
	}
	
}

  

结果:

 

求子集:

test1:

 

背包问题

 

npResult

 

posted @ 2017-05-10 22:27  cutter_point  阅读(170)  评论(0编辑  收藏  举报