题目链接:hdu 4960
使得整个数组成为一个镜面对称数组的最小代价
/******************************************************
* File Name: 1001.cpp
* Author: kojimai
* Creater Time:2014年08月19日 星期二 14时43分38秒
******************************************************/
/*
*给定一系列数,给定合并n个数的代价,让你最终整个数列变成一个镜面对称的数列
*区间DP,用dp[l][r]来表示把l到r范围的数组变成镜面对称所需要的最小代价
**每次找左右两边相等的区间和,能找到就剔除然后再找剔除之后的区间的最小值
*/
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
using namespace std;
#define FFF 5005
long long v[FFF],sum[FFF];
int a[FFF];
int n;
int dp[FFF][FFF];
long long getans(int l,int r)
{
if(r<l)
return 0;
if(dp[l][r]!=-1)//该区间的最小值已经找过那就直接返回就好
return dp[l][r];
long long ret=0;
long long tmp=-1;
int j=0;
for(int i=0;l+i<r-j&&(sum[l+i]-sum[l-1])<=(sum[r]-sum[l+i]);i++)
{
for(;r-j>i;j++)
{
if((sum[l+i]-sum[l-1])==(sum[r]-sum[r-j-1]))//从l到l+i的区间和以及从r-j到r的区间和相等则两者能够剔除
{
//ret=getans(l,l+i)+getans(l+i+1,r-j-1)+getans(r-j,r);
ret=a[i+1]+getans(l+i+1,r-j-1)+a[j+1];//左右两块区间直接合并,对中间的区间找并成镜面对称数组的最小代价
//cout<<l-1<<' '<<l+i<<' '<<r-j-1<<' '<<r<<' '<<ret<<endl;
if(tmp==-1)
tmp=ret;
else if(tmp>ret)
{
tmp=ret;
}
}
else if((sum[l+i]-sum[l-1])<(sum[r]-sum[r-j-1]))
break;
}
}
if(tmp==-1)
{
tmp=a[r-l+1];
}
if(tmp>a[r-l+1])//这题很坑的竟然合并多个点的代价反而可能小。。
tmp=a[r-l+1];
dp[l][r]=tmp;
//cout<<"l="<<l<<" r="<<r<<" b[l][r]="<<b[l][r]<<endl;
return dp[l][r];
}
int main()
{
sum[0]=0;
while(scanf("%d",&n),n)
{
memset(dp,-1,sizeof(dp));
for(int i=1;i<=n;i++)
{
//scanf("%I64d",&v[i]);
cin>>v[i];
sum[i]=sum[i-1]+v[i];
}
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
long long ans=getans(1,n);
cout<<ans<<endl;
}
return 0;
}