【PTA】K-背包问题

题目来源

作者: 陈晓梅
单位: 广东外语外贸大学
时间限制: 400 ms
内存限制: 64 MB
代码长度限制: 16 KB

问题描述

给定 n ( n < = 100 ) n(n<=100) n(n<=100)种物品和一个背包。物品 i i i的重量是 w i w_i wi,价值为 v i v_i vi,背包的容量为 C ( C < = 1000 ) C(C<=1000) C(C<=1000)。问:应如何选择装入背包中的物品,使得装入背包中物品的总价值最大? 在选择装入背包的物品时,对每种物品i只有两个选择:装入或不装入。不能将物品 i i i装入多次,也不能只装入部分物品 i i i

输入格式:
共有 n + 1 n+1 n+1行输入: 第一行为 n n n值和 c c c值,表示 n n n件物品和背包容量 c c c; 接下来的 n n n行,每行有两个数据,分别表示第 i ( 1 ≤ i ≤ n ) i(1≤i≤n) i(1in)件物品的重量和价值。
输出格式:
输出装入背包中物品的最大总价值。
输入样例:
在这里给出一组输入。例如:
5 10
2 6
2 3
6 5
5 4
4 6
输出样例:
在这里给出相应的输出。例如:
15

思路分析

这是一个K-背包问题,这里先列举一个例子解释下什么是K-背包问题。假设有一个小偷在商店里偷东西,但他的背包大小有限,只能一部分商品带走。每个商品不一样贵,问小偷如何赚的最多。如图所示,假设商店里有4件商品,每件的重量分别是3,5,4,9,价格分别是4,8,5,10。小偷的背包容纳的重量不超过20,所以不能把所有商品拿走,必须选择拿或不拿。
我们用如下的关系来表示:
在这里插入图片描述
在这里插入图片描述
从关系式中可以看出,从任意一个状态 B ( k , w ) B(k,w) B(k,w)开始,依次选择是否偷每个商品,如果不偷,则丢弃这个商品,对下个商品进行选择,如果偷,则比较偷和不偷的收益,其中最大的收益就是 B ( k , w ) B(k,w) B(k,w)的收益。
由于选择第 k k k个商品的收益时需要考虑第 k − 1 k-1 k1个商品,因此要计算收益 B B B ( k , w ) (k,w) (k,w)所有情况下的取值。因此可以建立二重循环,从 k = 1 k=1 k=1 w = 1 w=1 w=1开始,分别计算 B ( k i , w j ) B(k_i,w_j) B(ki,wj)。最终要求的结果就包含在这些 B ( k i , w j ) B(k_i,w_j) B(ki,wj)中。

算法实现

java

import java.io.*;
import java.util.Scanner;

public class Main {
public static void main(String[] argc) throws IOException
	{
			Scanner sc = new Scanner(System.in);
			int N = sc.nextInt()+1; 
			int W = sc.nextInt()+1;
			//要预留1位0
			int[] w = new int[N];
			int[] v = new int[N];
			for (int i=1;i<N;i++) {
				w[i]=sc.nextInt();
				v[i]=sc.nextInt();
			}
			
			System.out.println(knapsack(N,W,w,v));
			sc.close();
	}

	public static int knapsack(int N, int W, int[] w, int[] v) {
		int k, C;
		int[][] B = new int[N][W];// B自动初始化为0
		// k表示商品总数,在这里用于模拟从0到N的情况
		// C表示当背包容纳的重量,在这里C从1累加到W,用于模拟不同的背包大小
		for (k = 1; k < N; k++) {
			for (C = 1; C < W; C++) {
				if (w[k] > C) {// 如果第k件太重,则不偷,B不变
					B[k][C] = B[k - 1][C];
				} else {
					int value1 = B[k - 1][C - w[k]] + v[k]; // 偷第k件的总收益
					int value2 = B[k - 1][C]; // 不偷第k件的总收益
					if (value1 > value2) {
						// 选择偷和不偷的最大值
						B[k][C] = value1;
					} else {
						B[k][C] = value2;
					}
				}
			}
		}
		return B[N-1][W-1];
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值