题目描述
有P个牢房连接在一起, 每个牢房都有囚犯,现在要释放指定的Q个囚犯a1,a2,...aQ,但是为了避免发生暴动, 每个囚犯释放的时候必须给其他囚犯金币。相邻的囚犯在知道消息后必须得到金币,但是没得到消息的话就不需要给金币,所以需要给金币的情况是只要从释放囚犯向两边扩展直到末尾或空牢房。
问最优的情况下释放Q囚犯需要多少金币?
Input
The first line of input gives the number of cases, N(N表示有N个测试例子). N test cases follow. Each case consists of 2 lines. The first line is formatted as
P Q
where P is the number of prison cells (P是总的监狱数)and Q is the number of prisoners to be released(Q是要释放的罪犯个数).
This will be followed by a line with Q distinct cell numbers (of the prisoners to be released), space separated, sorted in ascending order.
Output
For each test case, output one line in the format
Case #X: C
where X is the case number, starting from 1, and C is the minimum number of gold coins needed as bribes.
Limits
1 ≤ N ≤ 100
Q ≤ P
Each cell number is between 1 and P, inclusive.
Small dataset
1 ≤ P ≤ 100
1 ≤ Q ≤ 5
Large dataset
1 ≤ P ≤ 10000
1 ≤ Q ≤ 100
#include<iostream> #include<vector> #include<stdio.h> #include<assert.h> using namespace std; const int MAXN = 1001; const int INT_MAX = 0x3f3f3f3f; int P, Q; int min(int a, int b) { if (a < b) return a; return b; } /* sample input: 20 3 3 6 14 20 20 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 10000 2 500 1500 sample output: 35 54 11497 */ int solve(vector<int>& A) { vector<vector<int> > dp(MAXN + 1, vector<int>(MAXN + 2, 0)); A[0] = 0, A[Q + 1] = P + 1; for (int i = 0; i <= Q; i++) { dp[i][i + 1] = 0; } for (int w = 2; w <= Q + 1; w++) { for (int i = 0; i + w <= Q + 1; i++) { int j = i + w, t = INT_MAX; for (int k = i + 1; k < j; k++) { t = min(t, dp[i][k] + dp[k][j]); } // based on the split position, and backtrack, you can recover the position of the best order. dp[i][j] = t + A[j] - A[i] - 2; } } return dp[0][Q + 1]; } int main() { while (cin >> P >> Q) { vector<int> A; A.resize(Q + 2); // assert(Q <= P); for (int i = 1; i <= Q; i++) { // A[i] = i; cin >> A[i]; } printf("%d ", solve(A)); } return 0; }