You Are the One(HDU 4283)

题意:

给出n个数,每个数字需要都需要进栈然后出栈。
第i个数出栈需要的花费是(i-1)*第i个出栈的权值
求所有数出栈需要的最小花费是多少?

分析:

栈能干什么呢,能把一个数字放进去然后过好久再放出来,但是把这个数字压进去的话压在更底下的数字就出不来了。
看起来挺复杂的= =
但是这题用不到这些东西

虽然说是栈,但是把每次清空栈之间看做一段区间,这些区间可以发现是相互独立存在的。而且这个区间里面怎么操作跟之后的结果无关。所以说可以考虑区间DP。

首先是状态的定义

这个大概还是挺套路的东西…dp[i][j]表示 i,j都出栈的最小值。
但是发现这里那个(i-1)挺麻烦的…而且之后这个[i,j]还可能前后移动然后改变,修改起来就很麻烦。方便起见,当做这个区间的开头就是1。
所以说dp[i][j]就是区间dp[i,j]都出栈所需要的最小花费,并且只有区间i,j

然后是找答案

这里的答案显然是dp[1,n]…这个大概是真的很套路的东西。

然后是初始化

dp[i][i]=a[i],求最小值,剩下的赋值成inf。

然后是关键的状态转移

对于每个子任务,求区间[l,r]的dp值。
想法还是把区间劈成两部分。然后考虑某一个数字出栈的位置。

code

#include<bits/stdc++.h>
#define M 105
#define pb push_back
#define ll long long
#define inf 1000000000 
using namespace std;

void read(int &x){
    x=0; char c=getchar();
    for (; c<'0'; c=getchar());
    for (; c>='0'; c=getchar())x=(x<<3)+(x<<1)+(c^'0');
}

int a[M],sum[M],dp[M][M];

int main(){
    int ca,i,l,k,n,t,s,s1,j;
    read(ca);
    for (t=1; t<=ca; t++){
        read(n);
        for (i=1; i<=n; i++)read(a[i]),sum[i]=sum[i-1]+a[i],dp[i][i]=0;
        for (i=1; i<=n; i++){
            for (j=i+1; j<=n; j++)dp[i][j]=inf;
        }
        for (l=1; l<=n; l++){
            for (i=1; i+l<=n; i++){
                j=i+l;
                for (k=i; k<=j; k++){   //i的位置上是k 
                                        //当k在i的时候且不考虑前面的东西的时候 
                                        //res=dp[i][k]+dp[k+1][j]+a[i]*(k-i)+(sum[k]-sum[i])*(k-i+1);
                    dp[i][j]=min(dp[i][j],dp[i+1][k]+dp[k+1][j]+a[i]*(k-i)+(sum[j]-sum[k])*(k-i+1));
                }           
            //  printf("%d-%d  %d\n",i,j,dp[i][j]); 
            }       
        }
        printf("Case #%d: %d\n",t,dp[1][n]);
    }
    return 0;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值