这道题目是刘汝佳算法入门中的一道动态规划题目。要求添加最少括号得到一个规则序列。先来看看它的状态转移,稍有复杂。
- 如果S是形如(S`)或[S`]的,就转移到d(S`)。
- 如果至少有两个字符,那么S可以分为A和B,转移到d(A)+d(B)。
边界条件就是S为空是d(S)为0,S位单字符时d(S)=1。另外需要注意的就是不管S是否进行第一种转移,都要尝试第二种转移。
<pre name="code" class="cpp">#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#define maxn 10000
using namespace std;
char s[maxn];
int d[maxn][maxn],n;
int match(int i,int j)
{
if((s[i]=='['&&s[j]==']')||(s[i]=='('&&s[j]==')')) return 1;
return 0;
}
void dp()
{
int i,j;
for(i=0;i<n;i++)//初始化数组d
{
d[i+1][i]=0;
d[i][i]=1;
}
for(i=n-1;i>=0;i--)
{
for(j=i+1;j<n;j++)
{
d[i][j]=maxn;
if(match(i,j)) d[i][j]=min(d[i][j],d[i+1][j-1]);//尝试第一种状态转移
for(int k=i;k<j;k++)
{
d[i][j]=min(d[i][j],d[i][k]+d[k+1][j]);//尝试第二种状态转移
}
}
}
}
void print(int i,int j)
{
if(i>j) return ;
if(i==j){
if(s[i]=='('||s[i]==')') printf("()");
else printf("[]");
return ;
}
if(match(i,j)&&d[i][j]==d[i+1][j-1]){//当前进行的是第一种转移时
printf("%c",s[i]);
print(i+1,j-1);
printf("%c",s[j]);
return;
}
for(int k=i;k<j;k++)
{
if(d[i][j]==d[i][k]+d[k+1][j]){//当前进行的是第二种转移时
print(i,k);
print(k+1,j);
return;
}
}
}
int main()
{
// freopen("input.txt","r",stdin);
int t,w;
scanf("%d\n",&t);
for(w=1;w<=t;w++)
{
gets(s);
n=strlen(s);
dp();
print(0,n-1);
printf("\n");
if(w!=t) printf("\n");
gets(s);
}
return 0;
}