HDU4283 You Are the One

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个点,每个点有一个权值,n个点会按照顺序出列,每个点第k个出列,花费为(k-1)*权值。但是我们有一个辅助工具,也就是一个栈,可以暂时把当前点压进栈,暂时不出列。问你能获得的最小花费是多少。

数据量是100.每个人出列顺序其实看以看成是向一个区间插入。

我们设dp[i][j]表示i-j这个区间的最小花费,那么考虑第i个人,它可以第一个。。。第j-i+1个上。

所以我们枚举插入的位置k,那么就会有:

dp[i][j] = 

1.左区间的代价dp[i+1][k] 加上

2.num[i]*(k-i)它自己的花费 加上 

3.右区间的花费dp[k+1][j] + (k-i+1)*(sum[j] - sum[k])这里为什么会加上后面一块,因为右区间这部分相当于是向右平移了k-i+1个位置,前面多了k-i+1个人。

然后看代码应该就懂了:

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <time.h>

using namespace std;
typedef long long LL;
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;
const int MAXN = 100+7;
int n;
int num[MAXN];
int sum[MAXN];
int dp[MAXN][MAXN];

int main()
{
    int t;
    scanf("%d",&t);
    int ca = 0;
    while(t--)
    {
        scanf("%d",&n);
        for(int i = 1; i <= n; ++i)
        {
            scanf("%d",&num[i]);
            sum[i] = sum[i-1] + num[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 i = n; i >= 1; --i)
            for(int j = i; j <= n; ++j)
                for(int k = i; k <= j; ++k)
        {
            dp[i][j] = min(dp[i][j],dp[i+1][k] + num[i]*(k-i) + dp[k+1][j] + (k-i+1)*(sum[j] - sum[k]));
        }
        printf("Case #%d: %d\n",++ca,dp[1][n]);
    }
    return 0;
}

嗯,区间dp感觉不是很容易建模,不过100基本就是带有k的3重循环,1000的数据基本就是两重循环的dp。

关于怎么看出是区间dp,我觉得还是要做题总结才行。





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值