题目传送门
区间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(" %d ",f[1][n]); sort(da+1,da+tot+1,cmp); for(int i = 1;i <= tot; i++) printf("%d ",da[i].v); return 0; }
#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(" %d ",f[1][n]); dd(1,n); return 0; }
100分和50分之间的区别在于第三问,题目中说要从左到右输出,而50分做法可能出现同级括号间从右到左的答案