dfs解决方案
外卖小哥的保温箱
http://www.nowcoder.com/questionTerminal/f3826b317d094e17a04e64a402bd0866
这道题的总体思路:
因为要求最少的保温箱,移动最少的次数。
首先按照保温箱的容量进行排序,排序完后就可以求的最少的保温箱个数。
但是后面不能直接把后面的保温箱直接移动到容量大的保温箱,因为虽然是最少保温箱个数,但是有可能有多种组合,举个例子
4 3 2 2 2 2
上面的如果要求货物总量为10个,那么后面四个箱子可以随意两个箱子,那么就可能有12中选择,
那么就要把所有满足要去的保温箱组合求出来,然后再让其中满足条件的组合中已经存放好的货物数量最大,这样需要移动的货物量就会变小。
如何求出满足条件的保温箱组合?通过DFS,但是这样时间复杂度其实是很高的,有O(nn-1n-2*n-k)个,所以还需要对后面剪枝,剪枝方案见代码。总体方案就是这样。
import java.util.*; public class Main { static int sum = 0; // 代表货物总数 static int k = 0; static ArrayList<ArrayList<Integer>> res = new ArrayList<>(); public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = sc.nextInt(); int[] a = new int[n]; int[] b = new int[n]; for (int i = 0; i < n; i++) { a[i] = sc.nextInt(); sum += a[i]; } Integer[] indexs = new Integer[n]; for (int i = 0; i < n; i++) { b[i] = sc.nextInt(); indexs[i] = i; } Arrays.sort(indexs, (o1, o2) -> b[o2] - b[o1]); int boxSum = 0; // 临时代表保温箱的货物总数 while (boxSum < sum) { boxSum += b[indexs[k]]; k++; } dfs(0, b, indexs, sum, new ArrayList<Integer>()); int maxAvailableSum = 0; for (ArrayList<Integer> boxes : res) { int curAvailableSum = 0; for (Integer box : boxes) { curAvailableSum += a[indexs[box]]; } maxAvailableSum = Math.max(curAvailableSum, maxAvailableSum); } System.out.format("%d %d", k, sum - maxAvailableSum); } public static void dfs(int watermark, int[] b, Integer[] indexs, int sum, ArrayList<Integer> box) { if (box.size() == k) { res.add(new ArrayList<Integer>(box)); return; } while (k - box.size() < b.length - watermark) { // 当剩余可添加的个数还充足时 if (b[indexs[watermark]] * (k - box.size()) < sum) { // 当剩余的怎么也填不满时,就直接返回 return; } box.add(watermark); dfs(watermark + 1, b, indexs, sum - b[indexs[watermark]], box); box.remove(box.size() - 1); watermark++; // 当前水位往后移动 } } }