01背包问题是一种最简单的背包问题,也是很常见的一种问题,一下分别通过遍历法,贪心算法和动态规划算法来解决这一问题。
1、遍历法:将所有组合的情况遍历一遍,为了方便,将每种组合对应一个二进制数,例如:某个背包问题中有abcde五种物品,那么00001代表只放入了a,10001代表放入了a物品和e物品。则一共有2^5=32种情况,求出每种情况下的背包总价值,记录下背包总价值最大的情况,即为最后结果。
Java代码:
public static void Traversal_method()
{
//存放二进制数的数组,每一个二进制数代表一种组合情况,例如00001代表只放入了a物品
String[] strs=new String[(int) Math.pow(2, list.size())];
//得到所有二进制数
for(int i=0;i<Math.pow(2, list.size());i++)
strs[i]=tobinary(i);
int maxvalue=0;
int index=0;
for(int count=0;count<strs.length;count++)
{
String s=strs[count];
//System.out.println("str="+s);
//如果某一位为1,则将其对应的物品放入背包,如果超重换下一种,同事记录下这种情况背包的总价值
for(int i=0;i<s.length();i++)
{
if(s.charAt(i)=='1')
if(!packet.putin(list.get(list.size()-i-1)))
break;
}
//记录背包最大总价值,及其对应的数字
if(packet.getValue()>maxvalue)
{
maxvalue=packet.getValue();
index=count;
}
//每种情况完成后,记得清理背包
packet.clear();
}
System.out.println("背包总价值最大为:"+maxvalue);
System.out.println("对应的二进制数:"+tobinary(index));
}<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>public static String tobinary(int num)
<span style="white-space:pre"> </span>{
String str ="";
while(num !=0){
<span style="white-space:pre"> </span>str =(num % 2) + str;
num =num/2;
}
while(str.length()<list.size())
<span style="white-space:pre"> </span>str="0"+str;
return str;
<span style="white-space:pre"> </span>}
2、贪心算法:根据物品的value/weight即单位重量的价值,将所有物品排序又大到小排列,性价比高的拍到最前,然后按照顺序依次放入背包,知道背包再放不下下一个物品停止。
Java代码:
public static void Greedy_method()
{
//冒泡排序,根据value/weight的大小从大到小排列
bubble_sort(list);
//按照顺序放入背包,知道背包再放不下下一个物品
for(int i=0;i<list.size();i++)
{
if(!packet.putin(list.get(i)))
break;
}
System.out.println("背包总价值最大为:"+packet.getValue());
}
<span style="white-space:pre"> </span>public static void bubble_sort(ArrayList<Item> list)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>for(int i=0;i<list.size();i++)
<span style="white-space:pre"> </span>for(int j=i;j<list.size();j++)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>if(list.get(i).getxingjiabi()<list.get(j).getxingjiabi())
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>Item temp=list.get(i);
<span style="white-space:pre"> </span>list.set(i, list.get(j));
<span style="white-space:pre"> </span>list.set(j, temp);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>}
3、动态规划算法:m为物品的序号,n为此时背包的最大承重,M为物品的总个数,N为背包的最大承重,w[m]=为第m个物品的重量,v[m]为第m个物品的价值,f[m][n]为有前m个物品,在放入最大承重为n的情况下的背包最大总价值。则算法描述如下:
f[m][n]矩阵
Java代码:
public static void DP_method()
{
int[][] packetmatrix=new int[list.size()+1][packet.getMAX_WEIGHT()+1];
for(int i=0;i<list.size()+1;i++){
for(int j=0;j<packet.getMAX_WEIGHT()+1;j++){
//为矩阵第0行,第0列赋初始值0
if(i==0 || j==0){
packetmatrix[i][j]=0;
//System.out.println("if "+packetmatrix[i][j]);
}
else{
//如果物品重量比背包总承重还要大,则矩阵此位置的值等于他上一行同列的值
if(list.get(i-1).getWeight()>j){
packetmatrix[i][j]=packetmatrix[i-1][j];
}
//否则,矩阵此位置的值等于max();
else{
packetmatrix[i][j]=Math.max(packetmatrix[i-1][j], packetmatrix[i-1][j-list.get(i-1).getWeight()]+list.get(i-1).getValue());
}
}
}
}
//输出表格
for(int i=0;i<list.size()+1;i++){
for(int j=0;j<packet.getMAX_WEIGHT()+1;j++){
System.out.print(packetmatrix[i][j]+" ");
}
System.out.println();
}
//根据表格得到那些物品被选中
int weight=packet.getMAX_WEIGHT();
for(int i=list.size();i>=1;i--)
{
//如果同一列,下面一行大于上面一行,说明该行对应的物品被选中
if(packetmatrix[i][weight]>packetmatrix[i-1][weight]){
packet.putin(list.get(i-1));
weight-=list.get(i-1).getWeight();
}
if(weight==0)
break;
}
System.out.println("maxvalue=="+packet.getValue());
}
全局静态变量,以及main方法:
static MyPacket packet=new MyPacket();
static ArrayList<Item> list=new ArrayList<Item>();
public static void main(String[] args)
{
Item a=new Item("a",2,1);
Item b=new Item("b",3,4);
Item c=new Item("c",6,6);
Item d=new Item("d",5,4);
Item e=new Item("e",4,6);
list.add(a);
list.add(b);
list.add(c);
list.add(d);
list.add(e);
//Traversal_method(); //遍历算法
//Greedy_method(); //贪心算法
DP_method(); //动态规划算法
}
背包类:
public class MyPacket {
private int weight;
private int value;
private final int MAX_WEIGHT=10;
public boolean putin(Item item){
if(this.weight+item.getWeight()<=MAX_WEIGHT){
System.out.println("放入物品:"+item.getName());
//items.add(item);
this.weight+=item.getWeight();
this.value+=item.getValue();
return true;
}else{
System.out.println("背包已满");
return false;
}
}
public void clear()
{
this.weight=0;
this.value=0;
}
public int getMAX_WEIGHT() {
return MAX_WEIGHT;
}
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;
}
}
物品类:
public class Item {
private int weight;
private int value;
private String name;
public Item(String name,int weight, int value) {
this.weight = weight;
this.value = value;
this.name = name;
}
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;
}
public float getxingjiabi()
{
return (float)value/(float)weight;
}
}