完全背包问题 AcWing(JAVA)

有 N种物品和一个容量是 V 的背包,每种物品都有无限件可用。

第 i 种物品的体积是 vi,价值是 wi。

求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。

输入格式 :

输出一个整数,表示最大价值。

数据范围:

0<N,V≤1000
0<vi,wi≤1000

输入样例 :

4 5

1 2 

2 4

3 4

4 5

输出样例: 

10

 解题思路:对于一个状态,考虑前i件物品,背包容量为j的情况下,所能装入的最大价值我们设为 f(i,j)。另外vi,wi分别代表着第i个物品的体积与价值。

刚好与我们设的数组f[][]对应。那么对于第i件物品我们有装与不装两种情况。

1.不装,那么最大价值就等于:考虑前i-1件物品,背包容量为j的情况下,所能装入的最大价值,对应f(i-1,j)。

2.装,由于物品无限多,所以又分为装1,2,....k个这些装法所对应的最大值分别为f(i-1,j-vi)+wi,f(i-1,j-2vi)+2wi,....f(i-1,j-kvi)+kwi。

综上:考虑前i件物品,背包容量为j的情况下,所能装入的最大价值:

一式:f(i , j) = max(f( i - 1, j),f(i - 1, j - vi) + wi ,f(i - 1,j - 2vi) + 2wi,....f(i - 1, j - kvi) + kwi)

这是一个状态方程:我们令j = j - vi ,代入上式得

二式:f(i , j - vi) = max(f(i - 1, j - vi) , f(i - 1,j - 2vi) + wi,....f(i - 1, j - kvi) + (k-1)wi,f(i - 1, j - (k+1)vi) + kwi)。

第i件物品最多只能装k件,所以二式中最后细字体一项不成立,舍去。

仔细观察二式中红色字体每一项都比下一项多一个wi,所以一式红色部分等效于f(i, j - vi) + wi。

所以一式优化后的方程为:f(i , j) = max(f( i - 1, j), f(i, j - vi) + wi)。

这就是完全背包问题的最优状态方程。

理论成立代码如下:

朴素版:

import java.util.*;
 
public class Main {
	public static int N = 1010;
    public static void main(String[] args) {
       Scanner sc  =  new Scanner(System.in);
       int n = sc.nextInt();
       int m = sc.nextInt();
       int v[] = new int[N];
       int w[] = new int[N];
       int f[][] = new int [N][N];//方程f(i,j)
       for(int i = 1; i <=n; i++) {
    	   v[i] = sc.nextInt();
    	   w[i] = sc.nextInt();
       }
       for(int i = 1; i<=n; i++)
    	   for(int j = 0; j<=m; j++) {
    		   f[i][j] = f[i-1][j];//不装
    		   if(j >= v[i])//符合条件才会考虑装入
    		   f[i][j] = Math.max(f[i][j], f[i][ j - v[i]]+w[i]);
    	   }
       System.out.print(f[n][m]);
	  }
}

值得一提的是01背包的状态方程为:f(i,j) = max(f(i - 1, j),f(i - 1, j - vi)+wi)。两者很相似但是有略微区别。 

精华版:

import java.util.*;
 
public class Main {
	public static int N = 1010;
    public static void main(String[] args) {
       Scanner sc  =  new Scanner(System.in);
       int n = sc.nextInt();
       int m = sc.nextInt();
       int v[] = new int[N];
       int w[] = new int[N];
       int f[] = new int [N];//方程f(i,j)
       for(int i = 1; i <=n; i++) {
    	   v[i] = sc.nextInt();
    	   w[i] = sc.nextInt();
       }
       for(int i = 1; i<=n; i++)
    	   for(int j = v[i]; j<=m; j++) f[j] = Math.max(f[j], f[ j - v[i]]+w[i]);
    	   System.out.print(f[m]);
	  }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值