Hdu 5115 ---区间dp(2014北京现场赛D题)

来源:互联网 发布:网络安全教育讲话稿 编辑:程序博客网 时间:2024/05/01 14:45

题意:
现在有n(2 <= n <=200)个狼排成一排,每个狼有其初始的攻击力。此外,每只狼还对其相邻的两只狼产生攻击力加成的效果。每只狼的当前攻击力等于自己的初始攻击力加上其相邻的狼的加成。 现在要杀狼,但每杀一头狼,都会承受该狼当前的伤害,问杀完这n只狼最少承受的伤害总值是多少?
思路:
由于每个阶段的决策不同,对于杀某一头狼所承受的伤害也可能不同。伤害加成方式类似于炉石传说的火舌图腾。贪心的策略是不正确的。现设计状态,假设dp[i][j]为保证i – j 区间外的狼不杀的前提下,杀死区间i – j之间的所有的狼所承受的最小的伤害。此处加粗的前提非常重要。因为杀死区间i — j所承受的伤害不仅取决于内部的决策顺序,也取决于区间外部的情况。若没有此前提则无法正确地状态转移。容易知道最后的ans等于dp[0][n -1];

现在来考虑状态的转移,由于需要保证dp[i][j]由自状态转移而来且区间i – j的状态仅仅取决于区间内部的决策顺序以及b[i-1]和b[j + 1], 枚举杀区间i – j 狼的过程中最后一个被杀死的狼k,可以保证dp数组含义的正确性。那么dp[i][j] = Min(dp[i][k - 1] + dp[k + 1][j] + a[k] + b[i - 1] + b[j + 1])
代码:

#include <cstdio>#include <cstring>using namespace std;const int len = 202;const int mm = 1000000007;int n;int a[len];int b[len];int dp[len][len];int mins(int a, int b){    return a < b ? a : b;}int dps(){    memset(dp, 0, sizeof(dp));    for(int i = 1; i <= n; i++)        for(int j = i; j <= n; j++)            dp[i][j] = mm;    for(int j = 1; j <= n; j++)        for(int i = j; i >= 1; i--)            for(int k = i; k <= j; k++)                dp[i][j] = mins(dp[i][j], dp[i][k - 1] + dp[k + 1][j] + a[k] + b[i - 1] + b[j + 1]);    return dp[1][n];}int main(){    int t;    scanf("%d", &t);    for(int i = 1; i <= t; i++)    {        scanf("%d", &n);        for(int j = 1; j <= n; j++)            scanf("%d", a + j);        for(int j = 1; j <= n; j++)            scanf("%d", b + j);        b[n + 1] = 0;//保证取b+1的值得时候不会被前面可能残留的b值覆盖,保证边界始终为0        printf("Case #%d: %d\n", i, dps());    }    return 0;}
0 0
原创粉丝点击