部分背包问题

1. 问题描述:

有n个物体,第i个物体的重量为wi,价值为vi。在总重量不超过C的情况下让总价值尽量高。

每一个物体都可以只取走一部分,价值和重量按比例计算。

求最大总价值

注意:每个物体可以只拿一部分,因此一定可以让总重量恰好为C

 

2. 背包问题是一个很经典的问题,其中背包问题有很多的变体,像部分背包问题,乘船问题等。这些问题都涉及到了求解出最优的解,那么这个时候就需要使用贪心策略来解决了。像这道题目一样,我们都是这样想的,要想总价值最大而且要组成目标质量,我们应该:拿较轻的物品并且这些物品的价值是比较大的,怎么样去表示较轻的物品但是它的价值比较大呢,这就涉及到了单位价值的问题,我们可以拿这个物品的价值 / 物品的重量那么这个时候就得到了单位价值,单位价值越大说明这个物品是较轻但是它的价值是比较大的,所以我们要优先选择这些物品,这就是贪心策略了,每一次都是拿取单位价值最大的,等到不能够拿整个物品的时候我们来选择这个物品的一部分来构成我们的目标重量,这样就得到了最终的答案了

确定了这个策略之后,我们需要对每个物品的单位价值进行排序,但是有可能控制台输入的是乱序的数据,排完序之后那么原来在一起的质量与价值就会乱了,不在一组了,这个时候就需要使用到面向对象的模式了,创建一个私有的内部类,把对象的属性绑定在一起,然后使用构造器来进行赋值,因为涉及到排序的问题所以要实现Compareable接口来自定义比较的规则,这个私有的内部类可以使用getPrice方法来表示单位价值,这样在自定义比较规则的时候直接对getPrice方法返回的值进行比较就可以了,排序之后那么原来在一起的质量与价值的物品就不会乱了

3. 具体的代码如下:(这里可以创建toString方法来查看排序后数组的情况)

import java.util.Arrays;
import java.util.Scanner;
public class Main{
	//这里贪心的策略是选择单位价值更高的物品,单位价值表示更轻但是价值更高
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		double w[] = new double[n];
		double v[] = new double[n];
		Obj objs[] = new Obj[n];
		for(int i = 0; i < n; i++){
			w[i] = sc.nextDouble();
		}
		for(int i = 0; i < n; i++){
			v[i] = sc.nextDouble();
		}
		for(int i = 0; i < n; i++){
			objs[i] = new Obj(w[i], v[i]);
			//输出对象中属性的值
		}
		int C = sc.nextInt();
		Arrays.sort(objs);
		for(int i = 0; i < n; i++){
			System.out.println(objs[i]);
		}
		double maxValue = 0;
		for(int i = n - 1; i >= 0; i--){
			//if条件表示可以拿当前这个物品
			if(C >= objs[i].w){
				C -= objs[i].w;
				maxValue += objs[i].v;
				//System.out.println(maxValue);
			}else{
				//单位价值乘以能够拿的质量
				//maxValue += (C * (objs[i].v / objs[i].w));
				//单位价值乘以能够拿取的重量
				maxValue += objs[i].v * (C / objs[i].w);
				break;
			}
		}
				System.out.println(maxValue);
				sc.close();
	}
	
	private static class Obj implements Comparable{
		double w;
		double v;
		public Obj(double w, double v) {
			this.w = w;
			this.v = v;
		}
		
		//这里与原来不同的是使用了getprice()方法来进行
		public double getPrice(){
			return v / (double)w;
		}

		@Override
		public int compareTo(Obj other) {
			if(this.getPrice() == other.getPrice()) return 0;
			else if(this.getPrice() < other.getPrice()) return -1;
			else return 1;	
		}

		//toString方法是为了在打印对象的时候能够打印出对象中属性的值
		@Override
		public String toString() {
			return "Obj [w=" + w + ", v=" + v + ", p  = " + getPrice() + "]";
		}
	}
}

测试数据:
5
1 2 3 4 5
3 4 3 1 4
10

控制台输出的应该是13.2

你可能感兴趣的:(贪心与动态规划)