HDU - 4283 You Are the One 区间dp

HDU - 4283 You Are the One 区间dp

题目链接
题目大意:有n个人排成一排要上台表演,每个人有一个屌丝值pi。第i个上台表演的人,他的不满意度为(i-1)*pi。
现在有一个类似于栈的黑屋子,你可以让某些人进入这个黑屋子。这些人要按照排的顺序来,那么对于排在最前面的人,
就有两个选择:
(1)让他直接上台表演;
(2)让他暂时进黑屋子。
现在请你选择一个合理的调度顺序,使得最后的总不满意度最小?
题目分析:
这个题啊 把我学区间dp的热情都浇灭了。。。
dp[i][j] 表示i~j这个区间里的最小不满意度。对于这个区间里面的第一个元素i,他有可能第一个上台,也有可能第2个第j - i + 1个上台。所以我们的第三重for循环来枚举他的上场顺序。
假设他第k个上场,那么第 i + 1 ~ i + k - 1,肯定在他之前,这时的花费就是dp[i + 1][i + k - 1]。第 i + k ~ j在他之后,而dp[i + k][j]表示的是他们里面的顺序从1开始的不满意值,现在原来第一个上场的变成了第k + 1个,所以要在原来的基础上加上(sum[j] - sum[k]) * (k - i + 1)。
其实我觉得到这里还是很好理解的,不好理解的是为什么这样做就是对的。
代码:

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int inf = 0x3f3f3f3f;
const int maxn = 100;

int dp[maxn][maxn], data[maxn], sum[maxn];

int main()
{
    int t, cas = 1;
    scanf("%d", &t);
    while(t--)
    {
        int n;
        scanf("%d", &n);
        memset(dp, 0, sizeof(dp));
        for(int i = 1; i <= n; i++) {
            scanf("%d", &data[i]);
            sum[i] = sum[i - 1] + data[i];
        }

         for(int i = 1; i<= n; i++)
            for(int j = i + 1; j <= n; j++)
            dp[i][j] = inf;

        for(int len = 2; len <= n; len++) {
            for(int i = 1; i <= n; i++) {
                int j = i + len - 1;
                if(j > n) break;

               for(int k = i; k <= j; k++) {
                    dp[i][j] = min(dp[i][j], (k - i) * data[i] + dp[i + 1][k] + (sum[j] - sum[k]) * (k - i + 1) + dp[k + 1][j]);
                }
            }
        }

        printf("Case #%d: %d\n", cas++, dp[1][n]);
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值