算法题:背包最大承重为20,算出装满水果后价格最高的组合,水果不能重复。

         这是一个面试笔试题,要求在1个钟之内完成,虽然我花了三天想办法解决了,但是我还是不能够在1个钟之内回想起来写出我的算法,因为算法很复杂,我不禁觉得出这题的公司是不是想招天才。


        水果信息: 

        李子,重量:4,价格:4500
        苹果,重量:5,价格:4700

        橘子,重量:2,价格:2250
        草莓,重量:1,价格:1100
        甜瓜,重量:6,价格:4940

        菠萝,重量:2,价格:3900

        西瓜,重量:6,价格:5800

        桃子,重量:3,价格:3700

        香蕉,重量:2,价格:3750
        梨子,重量:3,价格:3600

 

        我的解决办法是用回溯法。回溯法有什么用?之前我觉得除了能用来解决八皇后问题就没什么用处了。后来在我解决这个面试题的时候,我发现回溯法可以解决排列组合中的组合问题,而这道面试题中要求水果不能重复,正好是一个组合问题。和一般组合不一样的是,一般的组合的每个组合元素个数是固定的,而这道面试题只要重量不超过规定的重量就算是一个组合。

        代码:

package test;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

/**
 * 背包最大承重为20,算出装满水果后价格最高的组合,水果不能重复
 */
public class Fruit {
	private static int maxWeight = 20;
	private String name;
	private int price;
	private int weight;

	public Fruit(String name, int weight, int price) {
		this.name = name;
		this.weight = weight;
		this.price = price;
	}

	public String getName() {
		return name;
	}

	public int getPrice() {
		return price;
	}

	public int getWeight() {
		return weight;
	}

	public static void printMaxPriceFruits(List<Fruit> fruitList) {
		System.out.println("最优解为:");
		List<List<Fruit>> maxPriceBagLists = best(fruitList);
		for (List<Fruit> bagList : maxPriceBagLists) {
			for (Fruit fruit : bagList) {
				System.out.print(fruit.getName() + " ");
			}
			int totalWeight = 0;
			int totalPrice = 0;
			for (Fruit fruit : bagList) {
				totalWeight += fruit.getWeight();
				totalPrice += fruit.getPrice();
			}
			System.out.print("weight:" + totalWeight + " " + "price:"
					+ totalPrice);
			System.out.println();
		}
	}

	/**
	 * 用回溯法求出价格最高的组合
	 * 
	 * @param fruitList
	 *            所有水果的集合
	 * @return 返回价格最高的组合
	 */
	public static List<List<Fruit>> best(List<Fruit> fruitList) {
		// 初始化剩余可装重量
		int remainWeight = maxWeight;
		// 用于回溯法的数组
		int[] fruitArr = new int[fruitList.size()];
		// 初始化水果选择的起点
		for (int i = 0; i < fruitArr.length; i++) {
			fruitArr[i] = -1;
		}
		// 存放水果组合的背包集合
		List<Fruit> bagList = new ArrayList<Fruit>();
		//
		List<List<Fruit>> bagLists = new ArrayList<List<Fruit>>();
		// 从第一种水果开始选择
		int k = 0;
		/*
		 * 当有增加动作,此变量等于false(解锁),当确定组合则为true(加锁,确定组合后会删除最后一个元素继续判断,
		 * 有可能删除后的组合符合条件,但是这个组合不是最优解,因为这个组合之前可以添加水果)
		 */
		boolean lock = false;
		while (true) {
			fruitArr[k] += 1;
			// 所有水果都试过都不能继续添加进背包,则确定一个组合
			if (fruitArr[k] >= fruitList.size()) {
				if (k > 0) {
					if (!lock) {
						List<Fruit> copyBagList = new ArrayList<Fruit>();
						copyBagList.addAll(bagList);
						bagLists.add(copyBagList);
						// 打印组合
						for (Fruit fruit : bagList) {
							System.out.print(fruit.getName() + " ");
						}
						int totalWeight = 0;
						int totalPrice = 0;
						for (Fruit fruit : bagList) {
							totalWeight += fruit.getWeight();
							totalPrice += fruit.getPrice();
						}
						System.out.print("weight:" + totalWeight + " "
								+ "price:" + totalPrice);
						System.out.println();
						// ///////////////////////////////
						lock = true;
					}
					remainWeight += bagList.get(bagList.size() - 1).getWeight();// 可承重增加
					bagList.remove(bagList.size() - 1);// 背包集合去掉最后一个水果
					fruitArr[k] = -1;// 回归起点(这里是回溯法的步骤,这个算法可省去这个步骤)
					k--;// 目标更新为上一个水果,继续搜索可能性
				} else {// 如果回溯到背包第一个水果,且任何水果都尝试过了,则已经遍历所有可能的组合,跳出循环
					break;
				}
			}
			// 如果该水果能放入背包
			else if (fruitList.get(fruitArr[k]).getWeight() <= remainWeight) {
				bagList.add(fruitList.get(fruitArr[k]));// 添加进背包集合
				remainWeight -= fruitList.get(fruitArr[k]).getWeight();// 剩余承重
				lock = false;
				// 目标更新为背包的下一种水果
				k++;
				// 如果所有水果都能装入,则k++会溢出,说明背包容量大于等于所有水果重量的合直接返回
				if (k >= fruitArr.length) {
					bagLists.add(bagList);
					return bagLists;
				}
				// 设定下一个水果选择的起点
				fruitArr[k] = fruitArr[k - 1];
			}
		}
		return maxPriceBagLists(bagLists);
	}

	/**
	 * 计算最优解组合的集合
	 * 
	 * @param bagLists
	 *            所有可能的组合
	 * @return 返回价格最高的组合
	 */
	public static List<List<Fruit>> maxPriceBagLists(List<List<Fruit>> bagLists) {
		List<List<Fruit>> maxPriceBagLists = new ArrayList<List<Fruit>>();
		int maxPrice = 0;
		for (List<Fruit> bagList : bagLists) {
			int totalPrice = -1;
			for (Fruit fruit : bagList) {
				totalPrice += fruit.getPrice();
			}
			if (totalPrice == maxPrice) {
				maxPriceBagLists.add(bagList);
			} else if (totalPrice > maxPrice) {
				maxPrice = totalPrice;
				maxPriceBagLists.clear();
				maxPriceBagLists.add(bagList);
			}
		}
		return maxPriceBagLists;
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		Fruit li = new Fruit("李子", 4, 4500);
		Fruit ping = new Fruit("苹果", 5, 4700);
		Fruit ju = new Fruit("橘子", 2, 2250);
		Fruit cao = new Fruit("草莓", 1, 1100);
		Fruit tian = new Fruit("甜瓜", 6, 4940);
		Fruit bo = new Fruit("菠萝", 2, 3900);
		Fruit xi = new Fruit("西瓜", 6, 5800);
		Fruit tao = new Fruit("桃子", 3, 3700);
		Fruit xiang = new Fruit("香蕉", 2, 3750);
		Fruit pear = new Fruit("梨子", 3, 3600);
		List<Fruit> fruitList = new LinkedList<Fruit>();
		fruitList.add(li);
		fruitList.add(ping);
		fruitList.add(ju);
		fruitList.add(cao);
		fruitList.add(tian);
		fruitList.add(bo);
		fruitList.add(xi);
		fruitList.add(tao);
		fruitList.add(xiang);
		fruitList.add(pear);

		Fruit.printMaxPriceFruits(fruitList);
	}
}


郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。