问题描述:
你的面前有n颗宝石,价值各不同。但是你只有一个容量为w的背包。请问如何选取才能得到最大价值。
输入:
一行,包括两个数字。一个是宝石颗数,一个是背包容量。
接下来n行就是n颗宝石的重量以及价值。
输出:
输出背包能容纳的最大价值,以及确定入包的宝石
这是一道很典型的动态规划问题。学了点皮毛后再来看这道典型的背包问题,突然恍然大悟。
首先我们找到子问题: 前n颗宝石选取放入容量为w的背包能得到的最大价值,设为dp(n,w)。所以题目就是求 dp(n,w)
由于原问题与子问题只存在第n-1颗宝石有没被选入(宝石编号从0开始) 所以其状态转移方程为
dp(n,w)=max(dp(n-1,w),dp(n-1,w-weights(i-1))+values(i-1)) (条件是 weights(i-1)<剩余w)
所以其动态规划代码如下:
对于i=0 dp(0,w) 肯定等于0 没有什么意义
for(int i=1;i<=n;i++){
for(int j=0;j<=w;j++){
if(weights[i-1]<=j){
dp[i][j]=Math.max(dp[i-1][j],
dp[i-1][j-weights[i-1]]+values[i-1]);
}
}
}
那么如何将入包的宝石打印出来呢
加入宝石被选中入包了,那么 dp(i,w) 一定大于 dp(i-1,w)
所以代码如下
for(int i=n;i>0;i--){
if(dp[i][w]>dp[i-1][w]){
System.out.print(i-1+" ,");
w-=weights[i-1];
}
}
完整代码如下:
package com.luo.daily;
import java.util.Scanner;
public class BeiBao {
public static void main(String[] args) {
Scanner in=new Scanner(System.in);
while(in.hasNextInt()){
int n=in.nextInt();
int w=in.nextInt();
int[] weights=new int[n];
int[] values=new int[n];
int[][] dp=new int[n+1][w+1];
for(int i=0;i<n;i++){
int weight=in.nextInt();
int value=in.nextInt();
weights[i]=weight;
values[i]=value;
}
for(int i=1;i<=n;i++){
for(int j=0;j<=w;j++){
if(weights[i-1]<=j){
dp[i][j]=Math.max(dp[i-1][j],
dp[i-1][j-weights[i-1]]+values[i-1]);
}
}
}
System.out.println("最大能装:"+dp[n][w]);
System.out.print("第 ");
for(int i=n;i>0;i--){
if(dp[i][w]>dp[i-1][w]){
System.out.print(i-1+" ,");
w-=weights[i-1];
}
}
System.out.println("颗宝石被选中");
}
}
}