【題意】:給出k個郵筒,郵筒理論承受爆炸能力為m,實際上是[1,m]的某一個值。問,最壞情況下, 至少要用多少炸藥才能測試出郵筒的承受爆炸能力。
有幾點要注意:
1.如果郵筒可以承受x單位炸藥,必定可以承受1到x-1單位的炸藥。
2.除非郵筒某次測試中被炸毀,否則仍然當它是完好無缺的,可以繼續用于下一次測試。
【題解】:dp。
對于只有一個郵筒,我們只能由1,2,3,……,m-1,m測試,所以最壞情況就是(1+m) * m / 2。
設狀態dp[i][l][r] 表示當前還有 i 個郵筒,且承受能力在[l,r]內測試出承受爆炸能力所用的最少炸藥。
顯然:
i == 1時,dp[1][l][r] = (l + r) * (r - l + 1) / 2.
i >= 2時,我們就不需要從頭開始枚舉了,我們應該選擇一個最優的分界點去測試。
所以有 dp[i][l][r] = min(dp[i][l][r], s + max(dp[i][s+1][r], dp[i-1][l][s-1])), l <= s <= r;
這里說明一下,因為測試完點s之后,題目要求是最壞情況,所以只能選較大那個。
而外層的min是指,在這么多分界點之中,我們選取最優的分界點,這樣才能保證用最少炸藥。
【代碼】:
1 #include "iostream"
2 #include "cstdio"
3 #include "cstring"
4 #include "algorithm"
5 #include "vector"
6 #include "queue"
7 #include "cmath"
8 #include "string"
9 #include "cctype"
10 #include "map"
11 #include "iomanip"
12 using namespace std;
13 #define pb push_back
14 #define lc(x) (x << 1)
15 #define rc(x) (x << 1 | 1)
16 #define lowbit(x) (x & (-x))
17 #define ll long long
18 const int inf = 1 << 30;
19 int k, m;
20 int dp[11][101][101];
21
22 void init_dp() {
23 for(int r = 1; r <= 100; r++)
24 for(int l = 1; l <= r; l++)
25 dp[1][l][r] = (l + r) * (r - l + 1) / 2;
26
27 for(int i = 2; i <= 10; i++) {
28 for(int r = 1; r <= 100; r++) {
29 for(int l = r; l; l--) {
30 dp[i][l][r] = inf;
31 for(int s = l; s <= r; s++)
32 dp[i][l][r] = min(dp[i][l][r], s + max(dp[i][s+1][r], dp[i-1][l][s-1]));
33 }
34 }
35 }
36 }
37
38 int main() {
39 int T;
40 scanf("%d", &T);
41 init_dp();
42 while(T--) {
43 scanf("%d%d", &k, &m);
44 printf("%d\n", dp[k][1][m]);
45 }
46 return 0;
47 }
48