HDU 4283 You Are the One 区间DP

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 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

Sample Output

Case #1: 20
Case #2: 24 
  • 1
  • 2
  • 3

题目分析:

有n个人按照输入顺序排列,每个人有自身的愤怒值,你需要调整这个序列使愤怒值总和最小。 
乍一看,这不很简单吗 排个序就完事了。其实不然,因为这个调整序列不是随意调整的,是根据一个栈(相当与这n个人在栈内,你需要按照栈的规则调整顺序),那么这就是一道区间DP的题目了。 
思想不难,就是在每个区间[i][j]内,寻找一个位置k,将i放在k位置,那么在i到k之间的人需要在i排在这个人之前,在k+1到j之间的人在i这个之后,分别算这些人的愤怒值,这就是状态转移方程。

代码如下:

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
const int INF =0x3f3f3f3f;
const int MAXN =110;
using namespace std;
int T;
int n;
int a[MAXN];
int sum[MAXN];
int dp[MAXN][MAXN];
int main()
{
    scanf("%d",&T);
    for(int t=1; t<=T; 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<=n-l+1; i++)//区间起点
            {
                int j=i+l-1;//区间终点
                for(int k=1; k<=l; k++)//第i个人第k个上场
                {
                    dp[i][j]=min(dp[i][j],dp[i+1][i+k-1]+dp[i+k][j]+(k-1)*a[i]+(sum[j]-sum[i+k-1])*k);
                    //转移方程 表示第i+1个人到i+k-1个人在i之前上场 i+k到j个人在i之后上场 
                    //加上(k-1)*a[i]表示i的愤怒值 sum[j]-sum[i+k-1]*k表示i+k到j人在i以及i前的k-1个人总共k个人前
                }
            }
        }
        printf("Case #%d: %d\n",t,dp[1][n]);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40859951/article/details/82259878