HDU - 4283 You Are the One(区间DP)

题意:

给定 N N 个人,编号分别为1N,按顺序进栈,随意选择出栈顺序,每个编号为 i i 的人在第k个出栈时,其花费为: v[i](k1) v [ i ] ∗ ( k − 1 ) . 求所有可能的出栈顺序中,总花费的最小值?

思路:

非常好的DP题目,一旦想到状态定义后,后面的东西就简单了。
一开始,由于这个跟卡特兰计数非常相关,我自己想的定义 dp[i][j][k] d p [ i ] [ j ] [ k ] 为目前进栈了 i i 个出栈了j个,栈顶元素为 k k 情况下最小的花费值,有个问题就是必须得维护栈的状态,因为进行出栈操作后,就不知道次栈顶的元素是哪个了?维护栈的状态行不通,GG。
~~
正确的思路是区间DP:考虑区间第一个人是第几个出栈,由他产生的花费。记录dp[1][n]为所有人不同出栈顺序中最小的花费,那么设第一个人第 k k 个出场,则:[2,k]内这 k1 k − 1 个人一定在第一个人之前出场,且 [k+1,n] [ k + 1 , n ] 这些人一定在第一个人之后出场。然后考虑第一个人第 k k 个出场带来的花费:
1、第一部分,自身花费:v[1](k1)
2、第二部分,给后面出场的人带来的花费: k(sum[n]sum[k]) k ∗ ( s u m [ n ] − s u m [ k ] ) (sum为前缀和)

代码:

#include <bits/stdc++.h>
#define PB push_back
#define FT first
#define SD second
#define MP make_pair
#define INF 0x7fffffff
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int>  P;
typedef vector<int> VI;
typedef map<int,int> MII;
const int N = 105, MOD = 7+1e9;
int n, d[N][N], sum[N];
int ds[105];
int dp(int L, int R) 
{
    if(L >= R) return 0;
    if(d[L][R] != -1) return d[L][R];
    d[L][R] = INF;
    for(int i = L; i <= R; i++)
    {
        d[L][R] = min(d[L][R], dp(L+1, i) + (i-L)*ds[L] + dp(i+1, R) + (sum[R]-sum[i]) * (i+1-L));
    }
    return d[L][R];
}
int kase;
int main() 
{
#ifdef YUUKILP
    freopen("in.txt", "r", stdin);
#endif
    int t; cin >> t;
    while(t--) 
    {
        memset(d, -1, sizeof(d));
        cin >> n;
        for(int i = 1; i <= n; i++)
        {  
            cin >> ds[i];
            sum[i] = sum[i-1] + ds[i];  
        }
        printf("Case #%d: %d\n", ++kase, dp(1, n));  
    }
    return 0;  
}  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值