一、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();
}
}
複雜度分析
- 時間複雜度:,
- 空間複雜度:,
類似的問題還有:將一對數字分割爲兩個集合,兩個集合的最小差值(同樣也是 )