http://acm.hdu.edu.cn/showproblem.php?pid=4283.
题意:给一个序列数,按顺序不断的删除这些数,删除的消费为(index-1)*a[i] index为删除的次序(第几个删除),a[i] 为这个数的值, 你有一个栈,可以暂时存放一些数,也就是可以改变原来数删除的顺序,求最小的总消费
加入你有序列 1 2 3 4
我可以先把1删除(这时消费为(1-1)*1=0),把2放入栈内,这时可以选择把3放入栈内,也可以选择把3删除(这时消费为(2-1)*3=3),也可以选择把栈顶的2出队(2-1)*2=2)。等等
思路:区间dp
dp [i][j] 表示不考虑其他元素,删除i到j内元素的需要的最小总消费
sum [i][j] 表示i到j这段区间和(其实一维前缀和就可以)
t [i][j] 表示不考虑其他元素,按从j到i的顺序删除这些元素的消费和
dp[i][j] = min(dp[i] [k] + dp[k+1] [j] + sum[k+1] [j] * (k-i+1) , dp[k+1] [j] + t[i] [j] + sum[i] [j] * (j-k) )
其中dp[i] [k] + dp[k+1] [j] + sum[k+1] [j] * (k-i+1)是指先删除i到k段,在删除k+1到j段,
dp[k+1] [j] + t[i] [j] + sum[i] [j] * (j-k)是指先把i到j放入栈内,删除k+1到j段,在删除栈内(也就是逆序删除)
#include<bits/stdc++.h>
#define eps 1e-9
#define PI 3.141592653589793
#define bs 1000000007
#define bsize 256
#define MEM(a) memset(a,0,sizeof(a))
typedef long long ll;
using namespace std;
int dp[200][200];
int a[200];
int sum[200][200];
int temp[2][200][200];
void init(int x)
{
int i,j;
for(i=0;i<x;i++)
{
sum[i][i]=a[i];
temp[0][i][i]=0;
for(j=i+1;j<x;j++)
{
sum[i][j]=sum[i][j-1]+a[j];
temp[0][i][j]=temp[0][i][j-1]+(j-i)*a[j];
}
}
for(i=0;i<x;i++)
{
temp[1][i][i]=0;
for(j=i-1;j>=0;j--)
{
temp[1][j][i]=temp[1][j+1][i]+(i-j)*a[j];
}
}
}
int main()
{
int T,j,k,kk,i,n,ans=0;
cin>>T;
for(int t=1;t<=T;t++)
{
memset(dp,0,sizeof(dp));
ans=0;
cin>>n;
for(i=0;i<n;i++)
{
cin>>a[i];
}
init(n);
for(i=1;i<=n-1;i++)
{
for(j=0;j+i<n;j++)
{
int minn;
dp[j][j+i]=min(temp[0][j][j+i],temp[1][j][j+i]);
for(k=j;k<j+i;k++)
{
int now=min(dp[j][k]+dp[k+1][j+i]+(k-j+1)*sum[k+1][j+i],dp[k+1][j+i]+temp[1][j][k]+(j+i-k)*sum[j][k]);
dp[j][j+i]=min(dp[j][j+i],now);
}
}
}
printf("Case #%d: %d\n",t,dp[0][n-1]);
}
return 0;
}