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

题意:
现在有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 
#include 
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;
}

你可能感兴趣的:(dp,解题报告)