You Are the One HDU - 4283 区间dp

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;

 }


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值