HDU4283(区间DP)

题目链接

DP这东西还是一如既往的毁天灭地的难啊。

题意:有n个人参加非诚勿扰,每个人都有 n i 的屌丝值,如果前面有k个人比他早,他就会有 k 1 n i 的屌丝值,你可以让一些人进入一个小黑屋,来改变上场顺序,但是小黑屋是类似栈,先入后出。

题解:
dp[i][j]表示i~j区间的最优解。
对于i~j区间来说,第i个人可以第一个上,也可以最后一个(第j-i+1个)上,然后就需要枚举第i个人到底第几个上。

dp[i][j] = min(dp[i][j],dp[i + 1][i + k - 1] +num[i] * (k - 1) + dp[i + k][j] + k*(sum[j] - sum[i + k - 1]));

假设第i个人第k个上,那么就要增加(k-1)*num[i]的屌丝值,然后i+k~j的人之前有k个人,所以各自要增加k倍的屌丝值。
(之前我想的是在区间[i,j]枚举第k个人,然后在这个区间里最后一个上场,错的离谱。)
(总有一种自己DP越来越好一点的错觉。。。。但是还是一道题都想出不出来。好菜啊。。。。。

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int INF = 0x3f3f3f;
int n,num[105],dp[105][105],sum[105];

int main()
{
    int T,testCase = 1;;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        memset(dp,0,sizeof dp);

        for (int i = 1; i <= n; i++)
        {
            scanf("%d",&num[i]);
        }
        sum[0] = 0;
        for (int i = 1; i <= n; i++)
        {
            sum[i] = sum[i - 1] + num[i];
        }
        for (int i = 1;i <= n;i++)
        {
            for (int j = i + 1; j <= n; j++)
                dp[i][j] = INF;
        }
        for (int i = n; i >= 1; i--)
        {
            for (int j = i + 1; j <= n; j++)
            {
                for (int k = 1; k <= j - i + 1; k++)
                {
                    dp[i][j] = min(dp[i][j],dp[i + 1][i + k - 1] +num[i] * (k - 1) + dp[i + k][j] + k*(sum[j] - sum[i + k - 1]));
                }
            }
        }
        printf("Case #%d: %d\n",testCase++,dp[1][n]);
    }
}

猜你喜欢

转载自blog.csdn.net/meituanwaimai/article/details/80084863