题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=5115
题意:我们现在有n只排成一排的狼,对于第i只狼,他有两个伤害值 ai 和 bi 。当我们消去第i只狼是会受到 ai 的伤害以及 bi−1 和 bi+1 的伤害,如果我们要消去所有的狼,求受到的最小的伤害值。其中, 2≤n≤200 。
想法:这算是这个暑假做的最后一道题了,然后就开学了。由于放在了”DP好的请进”,所以很自然的就想dp了。由于消去每只狼时受到的伤害是由左中右三只狼共同决定的,那么我们考虑dp时的状态就要改变一下了。我们设dp[i][j]为消灭第i只到第j只狼所受到的最小伤害,那么答案即为dp[1][n]。那么转移时,我们来枚举i到j中间的被消灭的最后一只狼,那么转移方程即为dp[i][j] = min{dp[i][k-1] + dp[k+1][j] + a[k] + b[i-1] + b[j+1]},那么我们只需先枚举i到j的区间长度以及i和k即可,复杂度为 O(n) 。
代码如下:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
#include <cmath>
#include <cstdlib>
typedef long long ll;
const int MAXN = 300;
const int INF = (1 << 30);
int dp[MAXN][MAXN];
int a[MAXN], b[MAXN];
int main(){
//freopen("A.in", "r", stdin);
int cas, t = 0;
scanf("%d", &cas);
while(cas--){
int n;
scanf("%d", &n);
for(int i = 1; i <= n; ++i){
scanf("%d", a + i);
}
for(int i = 1; i <= n; ++i){
scanf("%d", b + i);
}
for(int i = 1; i <= n; ++i){
for(int j = 1; j <= n; ++j){
dp[i][j] = i <= j ? INF : 0;
}
}
for(int j = 0; j <= n; ++j){
for(int i = 1; i + j <= n; ++i){
for(int k = i; k <= i + j; ++k){
dp[i][i + j] = std::min(dp[i][i + j], dp[i][k - 1] + dp[k + 1][i + j] + a[k] + b[i - 1] + b[i + j + 1]);
}
}
}
printf("Case #%d: %d\n", ++t, dp[1][n]);
}
return 0;
}