本人做了这道题后发现这道题不仅涉及到括号匹配递归,又涉及刚学的平行四边形优化dp,于是来写题解。
小记
平行四边形优化是个玄学,主要看题感和运气,你觉得是就是,可以用这种优化的题主要有以下特征:
dp[i][j]=max/min(dp[i][j],dp[k][j-1]+w[k+1][i]);(k为1~n)
或
dp[i][j]=max/min(dp[i][j],dp[i][k]+dp[k+1][j]);(k为1~n)
如果该题符合平行四边形优化特点,k在(s[i-1][j]~s[i][j+1])之间。(s[i][j]表示i~j的最优分割点)。
题目描述
题目理解
我不说大家也看得出来,是经典的合并石子题,符合上方第二个dp,又用到每次加括号的位置,所以本来就会记录s[i][j]的平行四边形优化当然是首选,再用递归输出括号。
注:该题分割线尽量靠右,括号就会在左。(1,2,4,1,2)的最优解是[(((1+2)+4)+(1+2))]而非[((1+2)+(4+(1+2)))]
题目代码
#include<cstdio>
#include<algorithm>
using namespace std;
#define M (20 + 5)
#define LL int
inline void read(LL &x)
{
x=0;LL f=1;char c=getchar();
while(c<'0'||c>'9')
{
if(c=='-')
f=0-f;
c=getchar();
}
while(c>='0'&&c<='9')
{
x=x*10+c-'0';
c=getchar();
}
x*=f;
return ;
}
inline void write(int x)
{
if(x<10)
putchar(x+'0');
else{
write(x/10);
putchar(x%10+'0');
}
return ;
}
int n,a[M],v,ans,tp,dp[M][M],s[M][M],sum[M];
void dfs1(int l,int r)
{
if(l==r)
{
write(a[l]);
return ;
}
putchar('(');
dfs1(l,s[l][r]);
putchar('+');
dfs1(s[l][r]+1,r);
putchar(')');
return ;
}
void dfs2(int l,int r)
{
if(l==r)
return ;
dfs2(l,s[l][r]);
dfs2(s[l][r]+1,r);
write(sum[r]-sum[l-1]);
if(!(l==1&&r==n))
putchar(' ');
return ;
}
int main()
{
read(n);
for(int i=1;i<=n;i++)
read(a[i]),s[i][i]=i,sum[i]=a[i]+sum[i-1];//尺取法
for(int len=2;len<=n;len++)
for(int l=1;l+len-1<=n;l++)
{
int r=l+len-1;
dp[l][r]=0x3f3f3f3f;
for(int k=s[l][r-1];k<=s[l+1][r]&&k<r;k++)
if(dp[l][r]>=dp[l][k]+dp[k+1][r])
{
dp[l][r]=dp[l][k]+dp[k+1][r];
s[l][r]=k;
}
if(dp[l][r]==0x3f3f3f3f)
dp[l][r]=0;
dp[l][r]+=sum[r]-sum[l-1];
}
dfs1(1,n);
putchar('\n');
write(dp[1][n]);
putchar('\n');
dfs2(1,n);
}