算法题:背包最大承重为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); } }
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。