0-1背包问题(动态规划)

01背包 : 在 N 件物品,每件物品的重量为data[1][0],data[2][0]……data[n][0],与之相对应的价值为data[1][1],data[2][1]……data[n][1], 取出若干件放在 能装重量为 M 的背包里,求能装的最大价值为?

C 版:

#include <stdio.h>
#include <stdlib.h>
int max(int a,int b)
{ 
    if (a>b) 
    return a; 
    else return b;
}
int main()
{ 
     int n,m,i,j;
     int data[1001][2]; 
     int f[1001][1001];    //最优值矩阵,f[n][m]为最后所装最大价值 即 最优值 
     scanf("%d%d",&n,&m);  // n 表示n件物品,m 表示背包能背的最大重量 即 总承重    
     for(i=1;i<=n;i++) 
     {    
          scanf("%d%d",&data[i][0],&data[i][1]);  //每件物品的重量,价值 
     }   
     for(i=0;i<=m;i++) 
         f[0][i]=0; 
     for(i=0;i<=n;i++) 
         f[i][0]=0; 
     for(i=1;i<=n;i++)   
     {
         for(j=1;j<=m;j++)   
         {  
              f[i][j]=0;  
              if(j>=data[i][0]) //如果第 i 个物品重量 小于等于 总承重    
              {             
                    f[i][j]=max(f[i-1][j],f[i-1][j-data[i][0]]+data[i][1]);
                                  //按 f[i-1][j] 和 f[i-1][j-data[i][0]]+data[i][1] 哪个价值大,决定这件物品 是否被选择
                                  //f[i-1][j-data[i][0]]+data[i][1] 即 j-data[i][0]的重量能背的最大价值 + 这件物品的价值
                                  //f[i-1][j] 即 不装这件物品时的重量能背的最大价值
              }    
              else 
                    f[i][j]=f[i-1][j];   //如果第 i 个物品重量大于总承重
         }   
     }  
     printf("%d\n",f[n][m]); 
     system("pause"); 
     return 0;
}
测试输入:

8 13
3 20
4 8
2 11
5 15
3 6
1 7
1 12
4 18

输出:

68


Java版:

Goods.java

public class Goods {
	private int weight;
	private int value;
	public Goods(int weight,int value){
		this.weight = weight;
		this.value = value;
	}
	public int getWeight() {
		return weight;
	}
	public int getValue() {
		return value;
	}
	public String toString(){
		return "[weight: " + weight + " " + "value: " + value + "]";
	}
}
KnapsackProblem.java

import java.util.ArrayList;

public class KnapsackProblem {
	private Goods[] goods;      //物品
	private int totalWeight;    //totalWeight 表示背包能背的最大重量
	private int n;              // n 表示n件物品
	private int[][] bestValues; //最优值矩阵
	private int bestValue;      //最优值
	private ArrayList<Goods> bestSolution;//最优解的物品组成
	
	public KnapsackProblem(Goods[] goods, int totalWeight) {  
            this.goods = goods;  
            this.totalWeight = totalWeight;  
            this.n = goods.length;  
            if (bestValues == null) {  
                bestValues = new int[n+1][totalWeight+1];  
            }  
        }
	
	public void solve() {
		for (int i = 0; i <= n; i++) {
			bestValues[i][0] = 0;
		}
		for (int j = 0; j <= totalWeight; j++) {
			bestValues[0][j] = 0;
		}
		for (int i = 1; i <= n; i++) {         //同 C版 描述
			 for (int j = 1; j <= totalWeight; j++) {
				if (j >= goods[i - 1].getWeight()) {
  					int iweight = goods[i - 1].getWeight();
 					int ivalue = goods[i - 1].getValue();
					bestValues[i][j] = Math.max(bestValues[i - 1][j], bestValues[i - 1][j - iweight] + ivalue);
 				} else {
  					bestValues[i][j] = bestValues[i - 1][j];
 				}
 			}
		   }
		
		 bestValue = bestValues[n][totalWeight];
		
 		if(bestSolution == null){
			  bestSolution = new ArrayList<Goods>();
 		}
 		int tempWeight = totalWeight;
		for(int i=n;i >=1;i--){
  			if(bestValues[i][tempWeight] > bestValues[i-1][tempWeight]){
 				bestSolution.add(goods[i-1]);  // goods[i-1] 表示第 i 个物品  
	                        tempWeight -= goods[i-1].getWeight();
  			}
			if(tempWeight == 0){ 
 				 break; 
                        }
		}
 	}

 	public int[][] getBestValues() {
 		return bestValues;
 	}

 	public int getBestValue() {
		 return bestValue;
 	}

  	public ArrayList<Goods> getBestSolution() {
 		return bestSolution;
 	}
}
测试

KnapsackTest.java

public class KnapsackTest {

	public static void main(String[] args) {
	    Goods[] goods = new Goods[] {  
                    new Goods(3,20), new Goods(4,8),  
                    new Goods(2,11), new Goods(5,15),  
                    new Goods(3,6), new Goods(1,7),  
                    new Goods(1,12), new Goods(4,18)  
            };  
            int totalWeight = 12;  
        KnapsackProblem kp = new KnapsackProblem(goods, totalWeight);  
          
        kp.solve();  
        System.out.println(" -------- 该背包问题实例的解: --------- ");  
        System.out.println("最优值:" + kp.getBestValue());   
        System.out.println("最优解【选取的物品】: ");  
        System.out.println(kp.getBestSolution());  
        System.out.println("最优值矩阵:");  
        int[][] bestValues = kp.getBestValues();  
        for (int i=0; i < bestValues.length; i++) {  
            for (int j=0; j < bestValues[i].length; j++) {  
                System.out.printf("%-5d", bestValues[i][j]);  
            }  
            System.out.println();  
        }  
	}
}
输出:

 -------- 该背包问题实例的解: --------- 
最优值:68
最优解【选取的物品】: 
[[weight: 4 value: 18], [weight: 1 value: 12], [weight: 1 value: 7], [weight: 2 value: 11], [weight: 3 value: 20]]
最优值矩阵:
0    0    0    0    0    0    0    0    0    0    0    0    0    0    
0    0    0    20   20   20   20   20   20   20   20   20   20   20   
0    0    0    20   20   20   20   28   28   28   28   28   28   28   
0    0    11   20   20   31   31   31   31   39   39   39   39   39   
0    0    11   20   20   31   31   31   35   39   46   46   46   46   
0    0    11   20   20   31   31   31   37   39   46   46   46   52   
0    7    11   20   27   31   38   38   38   44   46   53   53   53   
0    12   19   23   32   39   43   50   50   50   56   58   65   65   
0    12   19   23   32   39   43   50   50   57   61   68   68   68   


时间复杂度为O(n*m),基本已经不能再优化了,但空间复杂度却可以优化到O(v)

改进版(将最优矩阵改为使用一维数组):

C++版:

#include <cstdio>
#include <cstring>
int bestValues[1005];
int main()
{
 int n,m;// n 表示n件物品,m 表示背包能背的最大重量 即 总承重
 int i,j;
 while(scanf("%d %d",&n,&m)&&(n+m))
 {
  int weight[1001],value[1001];
  for (i=1;i<=n;i++)
  {
   scanf("%d",&weight[i]);
   scanf("%d",&value[i]);
  }
  memset(bestValues,0,sizeof(bestValues));//数组初始化为0
  for (i=1;i<=n;i++)//从第一个物品开始一直到第n个物品
   for(j=m;j>=weight[i];j--)//从背包装满的状态开始,且第j个背包状态重量应该要大于等于第i个物品的重量
    if (bestValues[j-weight[i]]+value[i]>bestValues[j]){//如果第j-1个状态放入第i个的物品,并且放入后总价值大于第j个状态的价值
     bestValues[j] = bestValues[j-weight[i]]+value[i];  //则第j-1个状态时选择放入第i个的物品    
    }
 printf("%d\n",bestValues[m]);
 }
 return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值