题意:
给出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;
}