HDU 4283 You Are the One 详细题解

原题链接 HDU 4283

You Are the One

Time Limit: 2000/1000 MS (Java/Others)
Memory Limit: 32768/32768 K (Java/Others)
Problem Description
  The TV shows such as You Are the One has been very popular. In order to meet the need of boys who are still single, TJUT hold the show itself. The show is hold in the Small hall, so it attract a lot of boys and girls. Now there are n boys enrolling in. At the beginning, the n boys stand in a row and go to the stage one by one. However, the director suddenly knows that very boy has a value of diaosi D, if the boy is k-th one go to the stage, the unhappiness of him will be (k-1)*D, because he has to wait for (k-1) people. Luckily, there is a dark room in the Small hall, so the director can put the boy into the dark room temporarily and let the boys behind his go to stage before him. For the dark room is very narrow, the boy who first get into dark room has to leave last. The director wants to change the order of boys by the dark room, so the summary of unhappiness will be least. Can you help him?
Input
  The first line contains a single integer T, the number of test cases. For each case, the first line is n (0 < n <= 100)
  The next n line are n integer D1-Dn means the value of diaosi of boys (0 <= Di <= 100)
Output
  For each test case, output the least summary of unhappiness .
Sample Input
2    5 1 2 3 4 5 5 5 4 3 2 2
Sample Output
Case #1: 20 Case #2: 24

题意:有一队n个人,按照合理入栈出栈顺序上场,每个人有第一个屌丝值Di,每个人的愤怒值等于上场的顺序数k减1乘Di((k-1)*Di),求解可能的最小愤怒值总和。
分类:区间DP
思路

区间DP,自然要拆成小的区间来做,并且小的区间最优能构成大的区间最优,保证无后效性。那么就要找怎么拆分区间使得缩小问题规模。

设原来总区间为[1,n],其中一个子区间为[i,j],不考虑前面的区间,对与这个子区间最优,可以发现,这个子区间的愤怒值总和,只与这个子区间内的上场顺序有关。对于这个子区间,如果我们只考虑第i个人,那么它的上场顺序可能是第1个~第j-i+1个,设为k,这时,这个区间就被分为了两段,[i+1,k]和[k+1,j],也就是把[i+1,k]这所有人往前移动了一个,这同样是两个子问题,最终会分为[i,i+1]这种最小的子问题,再向下就是边界了,这时,只考虑,ii+1谁前谁后就好。然后两个子问题合并一个大问题,也就是把[i+1,k][k+1,j]合并为[i,j]

这样的话,就可以开一个二维数组,dp[i][j]就表示从i到j最小的愤怒值总和,dp[i+1][k]就表示这一段的最小愤怒值总和,并且,就在[i,j]这个区间的最前面所以,dp[i][j] 一部分为dp[i+1][k],然后是,[k+1,j]这一段,因为一段是在[i,j]的第k之后上场的,在子问题中并不考虑总体,所以, 在这里需要加上在总体中的顺序造成的愤怒值,所以这部分在[i,j]中的愤怒值总和为,dp[k+1][j]+(k-i+1)*(sum[j]-sum[k]),(sum[j]表示从1~j的屌丝值Dj总和),然后再加上第i个人的愤怒值,Di*(k-i)。总的来说就是,dp[i][j] = dp[i+1][k]+D[i]*(k-i)+dp[k+1][j]+(j-k+1)*(sum[j]-sum[k]), 这就是状态转移方程了。

边界也就是dp[i][i] = 0了, 因为只有一个人的队,这个人没有愤怒值。
注意,在所有考虑中,都是在只考虑[i,j]这一个区间的前提下进行的。

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int INF = (1<<27);
int n;
int a[105];
int sum[105];
int dp[105][105];
int main() {
    int _;
    scanf("%d", &_);
    for(int ka = 1; ka <= _; ka++) {
        scanf("%d", &n);
        for(int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
            sum[i] = sum[i-1]+a[i];
        }
        // 全局变量默认为0,并不更新为INF,所以,每次只需初始化其他状态点。
        for(int i = 0; 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 <= n-l; i++) {  // 起始位置
                int j = i+l;  // 终止位置
                for(int k = i; k <= j; k++)  // 第i个人在i-j中第k个上场
                    dp[i][j] = min(dp[i][j],
                      dp[i+1][k]+a[i]*(k-i)+dp[k+1][j]+(k+1-i)*(sum[j]-sum[k]));
            }
        }
        printf("Case #%d: %d\n", ka, dp[1][n]);
    }
    return 0;
}
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值