原题链接poj 1141 Brackets Sequence
由于对括号匹配的时候不只有一种方案,而本题要求要找最少的那种匹配方案,故可以用区间dp;
dp[i][j]表示从i到j之间为了匹配所需要的最少添加数。
状态转移方程 dp[i][j]=dp[i+1][j-1] (s[i]==s[j]);dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j])(i<=k<j);
又因为本题要输出匹配后的串,故需要把转移的路径记录下来,用pos[i][j]记录使dp[i][j]取最小值时的分开地方,
即上次动态转移方程中的最优的k值。然后递归输出。。。
参考代码:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define N 105 #define inf 0x7f7f7f7f using namespace std; char s[N]; int dp[N][N]; int pos[N][N]; char match(int c) { if(c=='(')return ')'; else if(c=='[')return ']'; else return 'x'; } void print(int l,int r) { if(dp[l][r]==0) { for(int i=l; i<=r; i++) printf("%c",s[i]); return; } if(l==r) { if(s[l]=='('||s[l]==')')printf("()"); else if(s[l]=='['||s[l]==']')printf("[]"); return ; } if(pos[l][r]==-1) { printf("%c",s[l]); print(l+1,r-1); printf("%c",s[r]); return ; } else { print(l,pos[l][r]); print(pos[l][r]+1,r); } return ; } int main() { //freopen("in.txt","r",stdin); scanf("%s",s); memset(dp,0,sizeof(dp)); memset(pos,0,sizeof(pos)); int n=strlen(s); for(int i=0; i<n; i++) { dp[i][i]=1; } for(int l=1; l<n; l++) for(int i=0; i+l<n; i++) { int j=i+l; dp[i][j]=inf; if(match(s[i])==s[j]) { dp[i][j]=dp[i+1][j-1]; pos[i][j]=-1; } for(int k=i; k<j; k++) if(dp[i][j]>dp[i][k]+dp[k+1][j]) { dp[i][j]=dp[i][k]+dp[k+1][j]; pos[i][j]=k; } } print(0,n-1); printf("\n"); return 0; }