hdu4283

区间dp。。。好难的说

这题目咋一看根本想不到是区间dp,我是做区间dp专题时看到的这题,但是就算知道是用区间dp做也划分不好状态,后来瞄了一眼状态划分,顿时被这题的思路惊呆了,将栈的特性应用的淋漓尽致,让人叹服。

题目分析:和普通的区间dp不同,这题无论任何情况下,都设当前区间最前面的一个元素为分割点,应用了栈的特性:若第一个元素第k个出栈,则第二到k个元素肯定在第一个元素之前出栈,第k+1到最后一个元素肯定在第k个之后出栈,这样便把区间划分成了两段,以此状态依次划分,加上记忆化搜索,便能得出答案。这题的记忆化搜索也和一般区间dp不同,区间内的值会随着区间之前共取出多少元素的改变而改变,故对要记忆的区间,记录下共有多少元素在此区间之前出栈,然后下次用到该区间是和记录的出栈元素个数比较,去掉多加或多减的部分,便能完成记忆化搜索。

#include <iostream>
#include <cstring>

using namespace std;

int dp[101][101];
int q[101];
int INF=0x3f3f3f3f;
int mark[101][101];
int sum[101];

int min(int a,int b)
{
    return a>b?b:a;
}

int interval(int l,int r,int k)
{
    if (l>r)
        return 0;
    if (mark[l][r]>=0)
    {
        int a=(k-mark[l][r])*(sum[r]-sum[l-1])+dp[l][r];
        return a;
    }
    dp[l][r]=INF;
    for (int i=1;i<=r-l+1;i++)
    { 
        int p=interval(l+1,l+i-1,k)+interval(l+i,r,k+i)+(i+k-1)*q[l];
        dp[l][r]=min(dp[l][r],p);
    }
    mark[l][r]=k;
    return dp[l][r];
}

int main()
{
    int T;
    cin>>T;
    for (int r=1;r<=T;r++)
    {
        int n;
        cin>>n;
        sum[0]=0;
        for (int i=1;i<=n;i++)
        {
            scanf("%d",&q[i]);
            sum[i]=sum[i-1]+q[i];
        }
        memset (dp,0,sizeof(dp));
        memset(mark,-1,sizeof(mark));
        interval(1,n,0);
        printf("Case #%d: %d\n",r,dp[1][n]);
    }
}


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值