HDU 4283 You Are the One(区间dp、状态转移)

来源:互联网 发布:java 多泛型 编辑:程序博客网 时间:2024/06/14 00:25

题目链接;
HDU 4283 You Are the One
题意:
【非诚勿扰?】
n个人需要上台,每个人的初始diaosi值(题目就这么说的)是data[i],如果i是第k个上场的话就会产生(k1)data[i]的愤怒值,但是允许先将某些人带进小黑屋中,后进后出原则,求所有人都上场的最小愤怒值之和?
数据范围:n100,data[i][0,100]
分析:
区间dp这种dp受制于状态转移过程一般的复杂度都是O(n3),并且第一层循环一般都是倒着递推
其主要难点也许在于如何确定状态转移,更具体的说,就是确定循环枚举的第三层的k的含义。一般都是指区间中的第k个位置。
但是这道题,我们首先可以把小黑屋看成一个栈,如果我们枚举区间第k个人是第一个上场的话,我们仍然不知道左右区间每个人的上场顺序,这样子左右区间就不是完全独立的了,不具备无后效性这个特点。
我们可以枚举第i个人是第k个上场的,那么区间[i+1,i+k1]k1个人一定是在i之前上场的,并且区间[i+k+1,j]的所有人一定是在i之后上场的,这样所有人的相对顺序就确定了.
对于子区间dp[i+k+1][j],我们是把它单独处理的,也就是得到这个最优解时第一个上场的确实是第一个上场的,但是如果想要由它转移到dp[i][j],那么第一个人实际上是第k+1个上场的,第二个人实际上是第k+2个上场的。。。。所以别忘了这种附加“属性”。

#include <iostream>#include <cstdio>#include <cstring>#include <string>#include <algorithm>#include <climits>#include <cmath>#include <ctime>#include <cassert>#define IOS ios_base::sync_with_stdio(0); cin.tie(0);using namespace std;typedef long long ll;const int MAX_N = 110;const int inf = 0x7fffffff;int T, n, cases = 0;ll data[MAX_N], sum[MAX_N], dp[MAX_N][MAX_N];int main(){    scanf("%d", &T);    while (T--) {        scanf("%d", &n);        sum[0] = 0;        for (int i = 1; i <= n; ++i) {            scanf("%lld", &data[i]);            sum[i] = sum[i - 1] + data[i];        }        for (int i = 0; i <= n; ++i) {            for (int j = 0; j <= n; ++j) {                if (i < j) dp[i][j] = inf;                else dp[i][j] = 0;            }        }        for (int i = n; i >= 1; --i) {            for (int j = i + 1; j <= n; ++j) {                for (int k = 1; k <= j - i + 1; ++k) {                    dp[i][j] = min(dp[i][j], data[i] * (k - 1) + dp[i + 1][i + k - 1] + dp[i + k][j] + k * (sum[j] - sum[i + k - 1]));                }            }        }        printf("Case #%d: %lld\n", ++cases, dp[1][n]);    }    return 0;}
0 0
原创粉丝点击