您的位置:首页 > 其它

hdu4283

2014-03-01 11:58 330 查看
区间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]
);
    }
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: