题目:
n 组测试数据,有p个人在监狱,要放出q个人,这些人的编号为a[1]~a[q],每放出一个人,他周围的人(两边连续的直到碰到空的监狱或者尽头)都要贿赂1枚金币,问最少花费多少金币。
思路:
dp[i][j]表示释放a[i]和a[j]之间的囚犯所需要的最少金币数。
初始化:dp[i][i+1]=0(因为a[i]和a[i+1]之间没有待释放囚犯),其他为INF。
动态方程:dp[i][j] = min(dp[i][j],dp[i][k]+dp[k][j]) + a[j] - a[i] - 2
(a[k]为a[i]和a[j]之间的一名待释放放囚犯)
AC代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
int n, p, q, a[105], dp[105][105];
int INF = 429496725;
int main()
{
int i, j, k, t;
scanf("%d", &n);
for(i = 1; i <= n; i++){
for(j = 0; j <= q + 1; j++){
fill(dp[j], dp[j] + 1 + q, INF);
}
scanf("%d %d", &p, &q);
for(j = 1; j <= q; j++){
scanf("%d", &a[ja]);
}
a[0] = 0;
a[q + 1] = p + 1;
for(j = 0; j <= q; j++){
dp[j][j + 1] = 0;
}
for(j = 2; j <= q + 1; j++){ //间隔j
for(k = 0; k + j <= q + 1; k++){
//释放a[k]到a[k + j]之间需释放的囚犯
int bribe = INF;
for(t = k + 1; t < k + j; t++){
bribe = min(bribe, dp[k][t] + dp[t][k + j]);
}
dp[k][k + j] = bribe + a[k + j] - a[k] - 2;
//两端不算(-1),被释放的囚犯不算(-1)
}
}
printf("Case #%d: %d\n", i, dp[0][q + 1]);
}
return 0;
}