给你一个括号序列,输出一个前后括号都匹配的补全序列,且补的字符尽量少。
对一个串s来说,只会有两种情况:1、(t)或【t】转移到t 2、有两个字符,分段转移。为了保证是最小值,一定要考虑情况二。
实际处理时,dp要开成二维,一个表示开头一个表示结尾。
吐槽一下UVA的输入输出,太恶心了成心卡你。
AC代码:
(非常抱歉不会用刘汝佳的输入)
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn=110;
char s[maxn];
int d[maxn][maxn];
int n;
int match(char a,char b)
{
return (a=='('&&b==')')||(a=='['&&b==']');
}
void dp()
{
for(int i=0;i<n;i++)
{
d[i][i]=1;
d[i+1][i]=0;//ÒâÒåΪºÎ£¿
}
for(int i=n-2;i>=0;i--)
for(int j=i+1;j<n;j++)
{
d[i][j]=n;
if(match(s[i],s[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;
}
int ans=d[i][j];
if(match(s[i],s[j])&&ans==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(ans==d[i][k]+d[k+1][j])
{
print(i,k);print(k+1,j);
return;
}
}
int main()
{
int t;
cin>>t;
getchar();
while(t--)
{
gets(s);
gets(s);
n=strlen(s);
memset(d,-1,sizeof(d));
dp();
print(0,n-1);
cout<<endl;
if(t) cout<<endl;
}
return 0;
}