一、Problem
给定一组石头,每个石头有一个正数的重量。每一轮开始的时候,选择两个石头一起碰撞,假定两个石头的重量为x,y,x<=y,碰撞结果为
- 如果x==y,碰撞结果为两个石头消失
- 如果x != y,碰撞结果两个石头消失,生成一个新的石头,新石头重量为y-x
最终最多剩下一个石头为结束。求解最小的剩余石头质量的可能性是多少。
输入描述:
第一行输入石头个数(<=100)
第二行输入石头质量,以空格分割,石头质量总和<=10000
输出描述:
最终的石头质量
输入例子1:
6
2 7 4 1 8 1
输出例子1:
1
二、Solution
方法一:贪心 + PQ(WA)
每次拿出两块质量最大的石头,如果质量不相同则进行碰撞,碰完加到堆中,可惜只能过 64% 样例…
import java.util.*;
import java.math.*;
import java.io.*;
public class Main{
static class Solution {
void init() {
Scanner sc = new Scanner(new BufferedInputStream(System.in));
int n = sc.nextInt();
Queue<Integer> q = new PriorityQueue<>((e1, e2) -> e2 - e1);
for (int i = 0; i < n; i++)
q.add(sc.nextInt());
while (q.size() > 1) {
int x = q.poll(), y = q.poll();
if (x > y)
q.add(x-y);
}
System.out.println(q.isEmpty() ? 0 : q.peek());
}
}
public static void main(String[] args) throws IOException {
Solution s = new Solution();
s.init();
}
}
复杂度分析
- 时间复杂度: ,
- 空间复杂度: ,
方法二:01 dp
我是在想不到背包,感觉这题考察的是问题的转化:微观来看,由于每次都是以两个为一组的石头进行相碰;宏观来看就是将所有石头分成两大堆进行碰撞,求如何分配才能让碰撞结果变得最小;
又由于最后最多会剩下一个石头,所以最后的结果要么是最小要么是 0,由此推出两大堆石头中质量较小的一堆的总质量 ,那如何才能让两堆石头的差值最小?答案是尽量让两堆石头的重量尽量接近,所以问题转化为:背包容量为 时,尽量最大化重量较小的一堆的石头的重量。
- 定义状态:
- 表示背包容量为 时,可收纳的最大重量的石头.
- 思考初始化:
- 思考状态转移方程:
- 对于第 堆石头,要么装下,要么不装。
- 思考输出: 表示
import java.util.*;
import java.math.*;
import java.io.*;
public class Main{
static class Solution {
void init() {
Scanner sc = new Scanner(new BufferedInputStream(System.in));
int n = sc.nextInt(), sum = 0, w[] = new int[n];
for (int i = 0; i < n; i++) {
w[i] = sc.nextInt();
sum += w[i];
}
int cap = sum >>> 1, f[] = new int[cap+1];
for (int i = 0; i < n; i++)
for (int j = cap; j >= w[i]; j--) {
f[j] = Math.max(f[j], f[j-w[i]] + w[i]);
}
System.out.println(sum - f[cap] - f[cap]);
}
}
public static void main(String[] args) throws IOException {
Solution s = new Solution();
s.init();
}
}
复杂度分析
- 时间复杂度: ,
- 空间复杂度: ,
类似的问题还有:将一对数字分割为两个集合,两个集合的最小差值(同样也是 )