参考:https://blog.youkuaiyun.com/changyuanchn/article/details/51417796
题目 /** * * [0-1背包问题]有一个背包,背包容量是M=150kg。有7个物品,物品不可以分割成任意大小。 * 要求尽可能让装入背包中的物品总价值最大,但不能超过总容量。 * 物品 A B C D E F G * 重量 35kg 30kg 6kg 50kg 40kg 10kg 25kg * 价值 10 40 30 50 35 40 30 */
其核心主要是如何穷举对象,对象有多少种组合排列,通过所有组合排列,遍历组合计算出最优的解
1.对象有多少种组合,一共有 n个物品 组合数量:C(0,n),C(1,n),C(2,n),……C(n-2,n),C(n-1,n),C(n,n) = 2^n
2.java 如何生成2^n种组合,参考https://blog.youkuaiyun.com/changyuanchn/article/details/51417796的实现,下列java代码中 genPowerSet 方法可得出组合,核心是通过0到2^n的二进制字符串遍历,可得每种组合,
3.计算出最优解
下面直接贴代码
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class Algorithm {
public static void main(String[] args) {
List<List<Greedy>> lists = greedyAlgorithm();//多个相同结果
for(List<Greedy> l : lists){
System.out.println("最优解组合:" + l);
}
}
/**
* 贪婪算法
* [0-1背包问题]有一个背包,背包容量是M=150kg。有7个物品,物品不可以分割成任意大小。
* 要求尽可能让装入背包中的物品总价值最大,但不能超过总容量。
* 物品 A B C D E F G
* 重量 35kg 30kg 6kg 50kg 40kg 10kg 25kg
* 价值 10 40 30 50 35 40 30
*/
public static List<List<Greedy>> greedyAlgorithm(){
String[] nameArr = new String[]{"A","B","C","D","E","F","G"};
int[] weightArr =new int[]{35,30,6,50,40,10,25};
int[] valueArr =new int[]{10,40,30,50,35,40,30};
//一共有 7个物品 组合C(0,7),C(1,7),C(2,7),C(3,7),C(4,7),C(5,7),C(6,7),C(7,7) = 2^7
List<Greedy> list = new ArrayList<>();
for(int i=0;i<nameArr.length;i++){
Greedy g = new Greedy();
g.setName(nameArr[i]);
g.setWeight(weightArr[i]);
g.setValue(valueArr[i]);
list.add(g);
}
List<List<Greedy>> lists = genPowerSet(list);
int maxValue = 0;
List<Integer> indexList = new ArrayList<>();//记录下标
for(int i=0;i<lists.size();i++){
int v = 0;//最优解价值
int w = 0;//最优解质量
for(Greedy g:lists.get(i)){
v += g.getValue();
w += g.getWeight();
}
if(w > 150){
continue;
}
if(v > maxValue){
indexList.add(i);
maxValue = v;
}
}
//不排除最大价值是相等的 质量不一样 或者品种不一样
//提取质量最轻
int value = lists.get(indexList.get(indexList.size()-1)).stream().mapToInt(Greedy::getValue).sum();//最优价值
int weight = lists.get(indexList.get(indexList.size()-1)).stream().mapToInt(Greedy::getWeight).sum();;//最后一条的质量
int j = indexList.size()-2;
List<Integer> resultIndex = new ArrayList<>();
resultIndex.add(indexList.get(indexList.size()-1));
do{
if(j<0){
break;
}
int v = 0;
int w = 0;
for(Greedy g : lists.get(indexList.get(j))){
v += g.getValue();
w += g.getWeight();
}
if( value > v){
break;
}else if(v == value ){
if(w == weight){//并列
resultIndex.add(j);
}else if(w < weight){//质量小于上一条
resultIndex.clear();
resultIndex.add(j);
}
}
j--;
}while (true);
return resultIndex.stream().map(e -> lists.get(e)).collect(Collectors.toList());
}
public static List<List<Greedy>> genPowerSet(List<Greedy> list){
List<List<Greedy>> resList = new ArrayList<>();
int maxNum = (2 << (list.size()-1));
for(int i=0;i<maxNum;i++){
List<Greedy> dataList =new ArrayList<>();
String binstr = toBinaryString(i,list.size());
for(int j=0;j<binstr.length();j++){
if("1".equals(binstr.toCharArray()[j]+"")){
dataList.add(list.get(j));
}
}
resList.add(dataList);
}
return resList;
}
//数字转换成二进制 n不足numDigitals位数时,前面补0
//例 toBinaryString(3,10) -> 0000000011
public static String toBinaryString(int n,int numDigitals){
String s = Integer.toBinaryString(n);
if(s.length()<numDigitals){
StringBuffer sb = new StringBuffer();
for(int i=0;i<numDigitals-s.length();i++){
sb.append("0");
}
sb.append(s);
return sb.toString();
}
return s;
}
static class Greedy{
private String name;
private int weight;
private int value;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
@Override
public String toString() {
return "Greedy{" +
"name='" + name + '\'' +
", weight=" + weight +
", value=" + value +
'}';
}
}
}
这篇博客主要介绍如何使用Java实现穷举算法来生成对象的所有可能组合,特别是当有n个物品时,组合数量为2^n。通过遍历0到2^n的二进制字符串,可以得到每种组合,从而找到最优解。文章提供了具体实现代码。
1856

被折叠的 条评论
为什么被折叠?



