#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 25;
int n, dp[maxn][maxn], gap[maxn][maxn];//g是断点位置
int ll[maxn], rr[maxn];//该位置数字的左/右括号数
int a[maxn], sum[maxn];//数字,前缀和
void dfs2(int x, int y);
void dfs1(int x, int y);
int main()
{
scanf("%d", &n);
int i, j, len, l, r, k;
sum[0] = 0;
memset(dp, 0x3f, sizeof(dp));
for(i = 1; i <= n; ++i)
{
scanf("%d", &a[i]);
sum[i] = sum[i-1]+a[i];
dp[i][i] = 0;//牢记
}
for(len = 2; len <= n; ++len)
for(l = 1; l+len-1 <= n; ++l)
{
r = l + len - 1;
for(k = l; k < r; ++k)
{
int tmp = dp[l][k]+dp[k+1][r]+sum[r]-sum[l-1];
if(tmp <= dp[l][r])
{//这里是<=, 而不是<, 能加括号的尽量加,因为要加满n-1个括号
dp[l][r] = tmp;
gap[l][r] = k;
}
}
}
dfs1(1, n);//求ll[]和rr[]
for(i = 1; i <= n; ++i)
{
for(j = 1; j <= ll[i]; ++j) printf("(");
printf("%d", a[i]);
if(!rr[i] && i != n) printf("+");
for(j = 1; j <= rr[i]; ++j) printf(")");
if(rr[i] && i != n) printf("+");
}
printf("\n%d\n", dp[1][n]);
dfs2(1, n);
return 0;
}
void dfs1(int x, int y)
{
if(x == y) return;
++ll[x],++rr[y];
dfs1(x, gap[x][y]);
dfs1(gap[x][y]+1, y);
}
void dfs2(int x, int y)
{
if(x == y) return;
dfs2(x, gap[x][y]);
dfs2(gap[x][y]+1, y);
printf("%d ", sum[y]-sum[x-1]);
}
洛谷P2308_区间dp_输出路径和中间过程
最新推荐文章于 2024-04-25 22:48:04 发布