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