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
