01背包问题 JAVA

【题目描述】

一个旅行者有一个最多能装 MM 公斤的背包,现在有 nn 件物品,它们的重量分别是W1,W2,...,WnW1,W2,...,Wn,它们的价值分别为C1,C2,...,CnC1,C2,...,Cn,求旅行者能获得最大总价值。

 

【输入】

第一行:两个整数,MM(背包容量,M<=200M<=200)和NN(物品数量,N<=30N<=30);

第2..N+12..N+1行:每行二个整数Wi,CiWi,Ci,表示每个物品的重量和价值。

 

【输出】

仅一行,一个数,表示最大总价值。

 

【输入样例】

10 4 
2 1
3 3
4 5
7 9

【输出样例】

12

在解决问题之前,为描述方便,首先定义一些变量:Vi表示第 i 个物品的价值,Wi表示第 i 个物品的体积,

定义V(i,j):当前背包容量 j,前 i 个物品最佳组合对应的价值

同时背包问题抽象化(X1,X2,…,Xn,其中 Xi 取0或1,表示第 i 个物品选或不选)。

1、建立模型,即求max(V1X1+V2X2+…+VnXn);

2、寻找约束条件,W1X1+W2X2+…+WnXn<capacity;

3、寻找递推关系式,面对当前商品有两种可能性:

  • 包的容量比该商品体积小,装不下,此时的价值与前i-1个的价值是一样的,即V(i,j)=V(i-1,j);

  • 还有足够的容量可以装该商品,但装了也不一定达到当前最优价值,所以在装与不装之间选择最优的一个,即V(i,j)=max{V(i-1,j),V(i-1,j-w(i))+v(i)}。

 

代码(还输出了图表,如要提交请去掉):

 1 import java.util.Scanner;
 2 public class test4 {
 3 ​
 4   public static void main(String[] args) {
 5     Scanner scan = new Scanner(System.in);
 6     System.out.println("请输入数据:");
 7     int m = scan.nextInt();//输入背包重量
 8     int n = scan.nextInt();//输入物品数量
 9     int[] w = new int[n + 1];//存放物品重量信息
10     w[0] = 0;
11     int[] v = new int[n + 1];//存放物品价值信息
12     v[0] = 0;
13     for(int i = 0;i < n;i++) {
14       w[i] = scan.nextInt();//输入第i个物品重量
15       v[i] = scan.nextInt();//输入第i个物品价值
16     }
17       scan.close();
18       Tools tool = new Tools();
19       System.out.println("背包能装下的最大价值为:" + tool.dp(w,v,m));
20   }
21 ​
22 }
23 class Tools{//dp先找状态转移公式,以i为容量,j为物品,w为重量,v为价值,V为总价值举例,状态转移方程为:当i < w[j]时 V[j][i] = V[j - 1][i]
24   //当i >= w[j]时 V[j][i] = Max(V[j - 1][i], 
25   //V[j - 1][i - w[j]] + v[j])
26   public int dp(int[] w,int[] v,int m) {
27     int[][] table = new int[w.length][m + 1];
28     //创建二维数组,实现所有情况:横向以此是背包载重,纵向是物品列表,将每次最优结果填充到该数组中
29     int[][] table = new int[w.length][max + 1];
30         for(int i=0;i<=max;i++){
31           //外层是背包的容量,依次从0-max,一个个测试
32            for(int j = 0;j<w.length;j++){
33            //每一次背包确定载重时,依次拿物品来装,取得当前载重最高价值
34               if(i == 0 || j == 0){//起始状态
35                  table[j][i] = 0;
36               }
37               else{
38                  //否则,开始判断当前物品能否放到当前背包中
39                  if(i < w[j]){
40                   //当前物品重量是超过背包重量的,则使用上一次最优结果
41                     table[j][i] = table[j - 1][i];
42                  }
43                  else{
44                   //否则,可以放也可以不放,取放与不放之间的最优解
45                     int v1 = table[j - 1][i];
46                    //不放,就使用前一次最大值
47                     int v2 = table[j - 1][i - w[j]] + v[j];
48                    //放,则将上一次最大价值加上本次价值
49                     table[j][i] = Math.max(v1, v2);
50                  }
51               }
52            }
53         }
54       for(int i = 0;i < w.length;i++) {//输出表
55         for(int j = 0;j <= max;j++)
56           System.out.print(table[i][j] + "\t");
57       System.out.println();
58       }
59    return table[w.length - 1][max];//返回最大物品价值
60   }
61 }

 


样例表输出:


0 0 0 0 0 0 0 0 0 0 0
0 0 1 1 1 1 1 1 1 1 1
0 0 1 3 3 4 4 4 4 4 4
0 0 1 3 5 5 6 8 8 9 9
0 0 1 3 5 5 6 9 9 10 12

 

上一篇:网络维护小工具---- IP SCAN


下一篇:计算机操作系统(复习)设备管理