You Are the One HDU - 4283 区间dp

开始读题读了半天,还是参考了大佬的博客
https://blog.csdn.net/codeswarrior/article/details/81479291
有一群屌丝,每个屌丝有个屌丝值,如果他第K个上场,屌丝值就为a[i]*(k-1),因为前面有k-1个人在他前面上台,可以把几个人拉进小黑屋来调整,可以把小黑屋当成栈因为先进去的人最后才能出来,使得最后总屌丝值最小

//定义dp[i][j]表示原序列区间[i,j]的人的最小屌丝值
//枚举一个中间变量k,设i在区间[i,j]中是第k个上场的
//这样区间分成了两部分
//dp[i+1][i+k-1](k-1个人在i之前),dp[i+k][j](之后的人)
//也就是让[i,i+k-1]这些人进入小黑屋
//i先进的,那么他前面将有k-1个人
//他是第k个上场的,之后再让后面的[i+k,j]这些人上场
//这样很明显i等待了k-1个人屌丝值增长为(k-1)×a[i],而[i+k,j]这些人则等待了k个人,屌丝值增长为k×(这些人的屌丝值之和)
//因此状态转移公式为
//dp[i][j]=min(dp[i][j],dp[i+1][i+k-1]+dp[i+k][j]+k×(sum[j]-sum[i+k-1])+a[i]×(k-1))
//sum[]记录了每个人屌丝值的前缀和
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int INF = 0x3f3f3f3f;
int n,a[105],sum[105],dp[105][105];
int main() {
    int t,cas = 0;
    scanf("%d",&t);
    while(t--) {
        scanf("%d",&n);
        memset(sum,0,sizeof(sum));
        for(int i = 1; i <= n; i++) {
            scanf("%d",&a[i]);
            sum[i] = sum[i-1] + a[i];
        }
        memset(dp,0,sizeof(dp));
        for(int i = 1; i <= n; i++) {
            for(int j = i + 1; j <= n; j++) {
                dp[i][j] = INF;
            }
        }
        //区间长度 
        for(int l = 1; l < n; l++)
            //左端点,      右端点 
            for(int i = 1; i + l <= n; i++) {
                //右端点 
                int j = i + l;
                //枚举中间量,第几个上场 
                for(int k = 1; k <= j - i + 1; k++) 
                    dp[i][j] = min(dp[i][j],dp[i+1][i+k-1]+dp[i+k][j]+k*(sum[j]-sum[i+k-1])+a[i]*(k-1));
            }
        
        printf("Case #%d: %d\n",++cas,dp[1][n]);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/QingyuYYYYY/p/12470257.html