快手Java工程师笔试题
问题描述
**给定一组石头,每个石头有一个正数的重量。每一轮开始的时候,选择两个石头一起碰撞,假定两个石头的重量为x,y,x<=y,碰撞结果为
- 如果x==y,碰撞结果为两个石头消失
- 如果x != y,碰撞结果两个石头消失,生成一个新的石头,新石头重量为y-x
最终最多剩下一个石头为结束。求解最小的剩余石头质量的可能性是多少。**
输入描述:
第一行输入石头个数(<=100)
第二行输入石头质量,以空格分割,石头质量总和<=10000
输出描述:
最终的石头质量
算法分析
根据分析可知,要求的最少剩余石头质量问题。可以考虑到是0-1背包问题。由两两石头相撞,可以考虑把石头分成两堆,两堆石头之间进行碰撞,如何分堆使碰撞之后石头最小的问题。两堆石头的总质量之和为sum,则两堆石头中质量最小的那堆的质量肯定不超过sum/2。为了使最终结果最小即两堆石头的质量之差最小,即求最小这堆石头的最大质量,当它最大质量为sum/2时,两堆石头相撞为0。
下面即求最小堆V1质量最大的问题,即0-1背包问题。从n个石头中挑选出最合适的组合使V1最大,且V1<=sum/2的问题。
具体代码如下
import java.util.Scanner;
public class Main{
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] v = new int[n];
//计算出所有石头的总质量
int sum = 0;
for (int i = 0; i < n; i++) {
v[i] = sc.nextInt();
sum+= v[i];
}
int arevge = sum/2;
//利用boolean数据记录石头组合的状态可能性
boolean[] status = new boolean[arevge + 1];
status[0] = true;
for (int i = 0; i < n; i++) {
for (int j = arevge; j >= v[i]; j--) {
//如果前面有组合使最小堆V1的质量等于status[j - v[i]]即值为true,则j - v[i]为true,则j - v[i]加上当前这块石头质量v[i]仍满足仍为true,则status[j] = true.
status[j]|= status[j - v[i]];
}
}
//利用循环挑选出能使最小堆V1最大的值
for (int i = arevge; i > 0; i--) {
if (status[i]) {
System.out.println(sum - i - i);
return;
}
}
}
}