算法題:揹包最大承重爲20,算出裝滿水果後價格最高的組合,水果不能重複。

         這是一個面試筆試題,要求在1個鐘以內完成,雖然我花了三天想辦法解決了,可是我仍是不可以在1個鐘以內回想起來寫出個人算法,由於算法很複雜,我不由以爲出這題的公司是否是想招天才。java

 

        水果信息: 面試

        李子,重量:4,價格:4500
        蘋果,重量:5,價格:4700算法

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

        菠蘿,重量:2,價格:3900ui

        西瓜,重量:6,價格:5800this

        桃子,重量:3,價格:3700code

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

 

        個人解決辦法是用回溯法。回溯法有什麼用?以前我以爲除了能用來解決八皇后問題就沒什麼用處了。後來在我解決這個面試題的時候,我發現回溯法能夠解決排列組合中的組合問題,而這道面試題中要求水果不能重複,正好是一個組合問題。和通常組合不同的是,通常的組合的每一個組合元素個數是固定的,而這道面試題只要重量不超過規定的重量就算是一個組合。get

        代碼:it

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);
	}
}

 

 

相關文章
相關標籤/搜索