MELON的难题_200分_B卷_回溯/dfs/递归

MELON的难题

题目描述:

MELON有一堆精美的雨花石(数量为 n,重量各异),准备送给 S和W。
MELON希望送给俩人的雨花石 重量一致,请你设计一个程序,帮MELON确认是否能将雨花石平均分配。

输入输出描述:

输入描述:

  第1行输入为雨花石个数:n, 0 < n < 31。
  第2行输入为空格分割的各雨花石重量:m[0] m[1]… m[n-1],0 < m[k] < 1001。不需要考虑异常输入的情况。

输出描述:

  如果可以均分,从当前雨花石中最少拿出几块,可以使两堆的重量相等;
  如果不能均分,则输出-1。

示例1:

输入:
	4
	1 1 2 2
输出:
	2
说明:
	输入第一行代表共4颗雨花石,
	第二行代表4颗雨花石重量分别为1、1、2、2。
	均分时只能分别为1,2,需要拿出重量为1和2的两块雨花石,所以输出2。

用例2:

输入:
	10
	1 1 1 1 1 9 8 3 7 10
输出:
	3
说明:
	输入第一行代表共10颗雨花石,
	第二行代表4颗雨花石重量分别为1、1、1、1、1、9、8、3、7、10。
	均分时可以1,1,1,1,1,9,7和10,8,3,也可以1,1,1,1,9,8和10,7,3,1,或者其他均分方式,但第一种只需要拿出重量
	为10,8,3的3块雨花石,第二种需要拿出4块,所以输出3(块数最少)。

解题思路:

总的思想是:贪心策略和回溯;
贪心体现在,从1,2,3,4…n/2 块石头开始尝试,一旦尝试成功,则就是最少的拿出石头的数量。
回溯则是体现在每次决定要拿几块、拿了之后还可以选择那些石头块。

回溯中参数要明确:
目标:要拿多少块石头,要筹齐的重量是多少。
当下的情况:已经拿了几块石头,这些石头有多重了,还能够拿哪些石头。
判别拿取方案是否可行:若刚好使用筹齐出目标重量,则说明方案可行。其他情况(如重量已经超出目标重量、石头块数量已经超出目标数量等)

代码:

public static void main(String[] args) {
	Scanner scanner = new Scanner(System.in);
	int n = Integer.parseInt(scanner.nextLine());
	String[] split = scanner.nextLine().split(" ");
	int[] stones = new int[n];
	int sum = 0;
	// 输入处理
	for (int i = 0; i < n; i++) {
		stones[i] = Integer.parseInt(split[i]);
		sum += stones[i];
	}

	// 不可以均分为重量相等的两堆石头
	if (sum % 2 != 0) {
		System.out.println(-1);
		return;
	}

	// 排序,
	Arrays.sort(stones);
	// 均分成两堆的重量
	int target = sum / 2;
	boolean avg = false;

	// 拿出去的石头数量:[1, n/2]
	for (int i = 1; i <= n / 2; i++) {
		if (dfs(stones, 0, i, 0, target, new boolean[n])) {
			System.out.println(i);
			avg = true;
			break;
		}
	}

	if (!avg) {
		System.out.println(-1);
	}
}

// 目标是拿出 total 块石头筹齐目标重量 target。    目前已经拿了 count 块石头,重量是 sum,具体是拿了哪些石头记录在 used 中
private static boolean dfs(int[] stones, int count, int total, int sum, int target, boolean[] used) {
	// 已经使用的石头数量超出限度
	if (count > total) {
		return false;
	}

	// 用了 total 块石头, 凑足了目标重量 target
	if (sum == target && count == total) {
		return true;
	}

	for (int i = 0; i < stones.length; i++) {
		if (!used[i]) {
			used[i] = true;
			if (dfs(stones, count + 1, total, sum + stones[i], target, used)) {
				return true;
			}
			used[i] = false;
		}
	}

	return false;
}

回溯/dfs相关题目

最大平分数组
星际篮球争霸赛
等和子数组最小和
无向图染色
最大岛屿体积
羊、狼、农夫过河
考古学家
叠积木
用户调度问题
报文解压缩
机器人走迷宫
迷宫问题
仿 LISP 运算
全排列
最大时间

你可能感兴趣的:(华为OD机试真题(Java,A卷+B卷),深度优先,华为od,华为,算法,java)