题意简述
给定一个括号序列(长度<=100<=100<=100),但是这个括号序列不一定匹配,请用最少的添加配好这个序列。输出配好的序列。
数据
输入
([(]([(]([(]
输出
()[()]()[()]()[()]
思路
这个。。。第一眼看到,栈?
仿佛不能做。。。但是这个题好像珂以区间DPDPDP?
dp[l][r]dp[l][r]dp[l][r]表示从lll到rrr的最优解,pos[l][r]pos[l][r]pos[l][r]表示lll到rrr取最优解时的断点(如果=−1=-1=−1就表示不需要断点)。
显然有边界dp[i][i]=1dp[i][i]=1dp[i][i]=1,因为长度为111的字符串无论如何都需要补一个使得能匹配。
考虑转移。
如果s[l]s[l]s[l]和s[r]s[r]s[r]能匹配,显然有dp[l][r]=dp[l+1][r−1]dp[l][r]=dp[l+1][r-1]dp[l][r]=dp[l+1][r−1],断点什么的就交给中间(即l+1l+1l+1到r−1r-1r−1)记录去吧,反正lll到rrr是不用记录的,直接pos=−1pos=-1pos=−1处理。
如果不能匹配,就要考虑别的情况了。显然,dp[l][r]=min{dp[l][k]+dp[k+1][j]}dp[l][r]=min\{dp[l][k]+dp[k+1][j]\}dp[l][r]=min{dp[l][k]+dp[k+1][j]},其中l<=k<rl<=k<rl<=k<r。一边枚举kkk,一遍记录最优断点,存到pospospos里面。
现在考虑如何输出解。
和 2003NOIP-TG加分二叉树 那个题类似,我们定义DFS(l,r)DFS(l,r)DFS(l,r)为输出lll到rrr的解的函数。
如果l>rl>rl>r,直接返回(不合FA♂)
如果l==rl==rl==r,那么一定要补上一个的。如果s[l]==(或)s[l]==(或)s[l]==(或),那么输出()()()。否则输出[][][]。
如果pos[l][r]=−1pos[l][r]=-1pos[l][r]=−1,记得是什么情况么?我们只要DFS(l+1,r−1)DFS(l+1,r-1)DFS(l+1,r−1),然后两边套上括号即可。当然,套那种括号就不用判了,根据pos[l][r]=−1pos[l][r]=-1pos[l][r]=−1的神奇性质,我们只要在两边套上s[l]s[l]s[l],s[r]s[r]s[r]就是那一对括号。
否则,十分简单,分两块即可。DFS(l,pos[l][r])DFS(l,pos[l][r])DFS(l,pos[l][r]),然后DFS(pos[l][r]+1,r)DFS(pos[l][r]+1,r)DFS(pos[l][r]+1,r)即可。
代码:
#include<cstdio>
#include<algorithm>
#include<cstring>
#define N 110
using namespace std;
namespace Flandle_Scarlet
{
char s[N];int n;
int dp[N][N];
int pos[N][N];
bool check(char x,char y)//判断x和y是否是匹配的括号
{
if (x=='(' and y==')') return 1;
if (x=='[' and y==']') return 1;
return 0;
}
void DP()
{
memset(dp,0,sizeof(dp));
for(int i=0;i<n;++i)
{
dp[i][i]=1;//边界条件
}
for(int len=1;len<n;++len)//枚举长度
{
for(int l=0;l+len<n;++l)//枚举左端点
{
int r=l+len;//计算右端点
dp[l][r]=0x7fffffff;//初始化很大
if (check(s[l],s[r]))//如果s[l]和s[r]能匹配
{
if (dp[l+1][r-1]<dp[l][r])//就要考虑用dp[l+1][r-1]更新dp[l][r]
{
dp[l][r]=dp[l+1][r-1];
pos[l][r]=-1;
}
}
for(int k=l;k<r;++k)//枚举断点k
{
if (dp[l][r]>dp[l][k]+dp[k+1][r])
{
dp[l][r]=dp[l][k]+dp[k+1][r];
pos[l][r]=k;//更新答案
}
}
}
}
}
void DFS(int l,int r)//都解释过,此处注释略
{
if (l>r) return;
if (l==r)
{
if (s[l]=='(' or s[r]==')')
{
printf("()");
}
else
{
printf("[]");
}
return;
}
else if (pos[l][r]==-1)
{
putchar(s[l]);
DFS(l+1,r-1);
putchar(s[r]);
}
else
{
DFS(l,pos[l][r]);
DFS(pos[l][r]+1,r);
}
}
void Main()
{
while(gets(s)!=NULL)//听说不gets会炸(白费我10次提交)
{
n=strlen(s);
DP();
DFS(0,n-1);
putchar('\n');//结构清晰
}
}
}
int main()
{
Flandle_Scarlet::Main();
return 0;
}
1510

被折叠的 条评论
为什么被折叠?



