洛谷 P2308 添加括号

题目传送门

区间DP,f[i][j]表示i~j区间最小答案,用ans[i][j]记录f[i][j]的断点在哪里,即括号分界处.

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

int n,a[21],f[21][21],pre[21],be[21],c[21];
int ans[21][21],tot,kk[21][21];
struct kkk{
    int v,jl;
    kkk() {
        v = 0;
        jl = 0;
    }
}da[21];

inline void dfs(int x,int y) {
    if(x == y) return ;
    pre[x]++;
    be[y]++;
    da[++tot].jl = y - x + 1;
    da[tot].v = a[y] - a[x-1];
    dfs(x,ans[x][y]);
    dfs(ans[x][y] + 1,y);
}

inline bool cmp(kkk a,kkk b) {
    return a.jl < b.jl;
}

int main() {
    memset(f,0x3f3f3f,sizeof(f));
    scanf("%d",&n);
    for(int i = 1;i <= n; i++) {
        scanf("%d",&c[i]);
        a[i] = a[i-1] + c[i];
        f[i][i] = 0;
    }
    for(int len = 1;len <= n; len++)
        for(int i = 1,j = i + len;j <= n; i++,j++)
            for(int k = i;k < j; k++)
                if(f[i][j] >= f[i][k] + f[k+1][j] + a[j] - a[i-1]) {
                    f[i][j] = f[i][k] + f[k+1][j] + a[j] - a[i-1];
                    ans[i][j] = k;
                }
    dfs(1,n);
    for(int i = 1;i <= n; i++) {
        while(pre[i]--)
            printf("(");
        printf("%d",c[i]);
        while(be[i]--)
            printf(")");
        if(i != n) printf("+");
    }
    printf("\n%d\n",f[1][n]);
    sort(da+1,da+tot+1,cmp);
    for(int i = 1;i <= tot; i++)
        printf("%d ",da[i].v);
    return 0;
}
50分
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

int n,a[21],f[21][21],pre[21],be[21],c[21];
int ans[21][21],tot,kk[21][21];

inline void dfs(int x,int y) {
    if(x == y) return ;
    pre[x]++;
    be[y]++;
    dfs(x,ans[x][y]);
    dfs(ans[x][y] + 1,y);
}

inline void dd(int x,int y) {
    if(x == y) return ;
    dd(x,ans[x][y]);
    dd(ans[x][y] + 1,y);
    printf("%d ",a[y] - a[x-1]);
}

int main() {
    memset(f,0x3f3f3f,sizeof(f));
    scanf("%d",&n);
    for(int i = 1;i <= n; i++) {
        scanf("%d",&c[i]);
        a[i] = a[i-1] + c[i];
        f[i][i] = 0;
    }
    for(int i = 1;i <= n; i++)
        f[i][i+1] = a[i+1] - a[i-1],ans[i][i+1] = i;
    for(int len = 2;len <= n; len++)
        for(int i = 1,j = i + len;j <= n; i++,j++)
            for(int k = i;k < j; k++)
                if(f[i][j] >= f[i][k] + f[k+1][j] + a[j] - a[i-1]) {
                    f[i][j] = f[i][k] + f[k+1][j] + a[j] - a[i-1];
                    ans[i][j] = k;
                }
    dfs(1,n);
    for(int i = 1;i <= n; i++) {
        while(pre[i]--)
            printf("(");
        printf("%d",c[i]);
        while(be[i]--)
            printf(")");
        if(i != n) printf("+");
    }
    printf("\n%d\n",f[1][n]);
    dd(1,n);
    return 0;
}
AC代码

100分和50分之间的区别在于第三问,题目中说要从左到右输出,而50分做法可能出现同级括号间从右到左的答案

posted @ 2020-09-02 21:43  Mr^Simon  阅读(101)  评论(0编辑  收藏  举报