本来一个括号匹配的题目,在学习完数据结构的栈之后,我以为自己无敌了,直接一个栈上去
Time Limit Exceeded
..........
当时我稍微想了下为啥,没想出来,趁现在写博客的时候再想想看,
............
还是想不出来
后来发现,我学的那个栈的方法好像只能用来检测括号序列是否匹配,但是无法做到最小匹配....
然后发现POJ上还有一个题目2955,似乎是这个题目的简化版本
要求是找到括号序列的一个最大子列的长度,使这个子列中的括号是匹配好的
这个问题的解决详见我的另一篇博客POJ2955
解决了这个问题之后,自然想到两个问题的联系
如果我找到了最长的匹配的子列,剩下的括号不就是无法匹配的最少的括号吗?
只要给这些括号匹配好,那不就是最短的括号序列吗?
然而两题还是有很大差别,因为在POJ2955中,我们只是算出了最大的序列长度,而没有记录匹配的模式等信息,
比方说哪个括号和哪个括号匹配,哪个括号无法匹配等等在解决POJ1141很必要的信息。
但是没关系啊,因为在2955的基础上,我们只要添加一个记录匹配括号和非匹配括号的数组就行了
在2955 dp1的基础上,令dp2 [ i ] [ j ] [ 101 ] 记录从第 i 个括号到第 j 个括号中能匹配的括号的数组,
比方说在第 i 个到第 j 个括号的序列中,如果第k个括号能够找到他的匹配括号,则dp2[ i ][ j ][ k ]=1,否则为0
同2955的dp过程,对于dp2 [ i ][ j ] ,显然 dp2[ i ] [ i ] = 0,(现在是对整个101个数字的复制)有
1.dp2 [ i ] [ j ] = dp2 [ i ] [ j-1 ],当第 j 位出现的括号是左括号'('或者'['的时候,匹配的模式是不变的
2.dp2 [ i ] [ j ] [ i~(k-1)] = dp2 [ i ][ k-1 ][ i~(k-1)] dp2 [ i ] [ j ] [ (k+1)~(j-1)] = dp2 [ k+1 ][ j-1 ][ (k+1)~(j-1)] dp2 [ i ][ j ][ k ] = dp2 [ i ][ j ][ j ]=1,else
其中 k 是使得 dp1 [ i ][ j ]最大的那个 k,在POJ1141中有写,上式可以理解为 i ~ j 以 k为断点,则dp2 [ i ] [ j ] 就分成了 i~k-1 k+1~j-1 和 k, j 四个部分
这样最后只要检查 dp2 [ 1 ] [ len ] [ 1~len] 中如果为1 则直接输出,如果为0,该位如果位'('或')'就输出"()"其他情况则输出"[]"。
要考虑空输入的情况,真是坑爹.......
空间优化
光是这样空间有4000K,时间79ms,时间主要花在dp2整个数组的拷贝上,考虑到dp2只是标记0 1 所以改成 bool型就可以了,
这样空间变成了1200K,时间32ms
然后再考虑到 i比j小,所以 dp1 和 dp2 实际上是上三角矩阵,将上三角矩阵 dp2[ i ][ j ][ 100 ]映射到 二维数组 dp2[ (i-1)*100+j-i*(i-1)/2][ 100 ],
对dp1也是一样,然后
空间756K,时间16ms,
感觉跟别人的答案的消耗有点差不多了(一开始看到4000K吓坏了,虽然是意料之中.........)
附代码如下
#include<iostream>
#include<string>
#include<memory.h>
using namespace std;
int dp[5051];
bool dp2[5051][101];
int main()
{
char s[102];
cin.getline(s,101);
if(!strcmp(s,"\0")){
cout<<endl;
return 0;
}
int len=1;
while(s[len]!='\0'){
len++;
}
for(int i=len;i>=1;i--){
s[i]=s[i-1];
}
memset(dp,0,sizeof(dp));
memset(dp2,0,sizeof(dp2));
for(int j=2;j<=len;j++){
for(int i=j-1;i>=1;i--){
int flag=0;
int krec;
dp[(i-1)*100+j-i*(i-1)/2]=dp[(i-1)*100+j-1-i*(i-1)/2];
for(int t=i;t<=j;t++){
dp2[(i-1)*100+j-i*(i-1)/2][t]=dp2[(i-1)*100+j-1-i*(i-1)/2][t];
}
if(s[j]=='['||s[j]=='('){
continue;
}
else{
for(int k=i;k<j;k++){
if((s[k]=='['&&s[j]==']')||(s[j]==')'&&s[k]=='(')){
if(2+dp[(i-1)*100+k-1-i*(i-1)/2]+dp[k*100+j-1-(k+1)*k/2]>dp[(i-1)*100+j-i*(i-1)/2]){
krec=k;
flag=1;
dp[(i-1)*100+j-i*(i-1)/2]=2+dp[(i-1)*100+k-1-i*(i-1)/2]+dp[k*100+j-1-(k+1)*k/2];
}
}
}
}
if(flag==1){
for(int t=i;t<=j;t++){
if(t<krec){
dp2[(i-1)*100+j-i*(i-1)/2][t] = dp2[(i-1)*100+krec-1-i*(i-1)/2][t];
}
else{
dp2[(i-1)*100+j-i*(i-1)/2][t] = dp2[(krec)*100+j-1-(krec+1)*krec/2][t];
}
}
dp2[(i-1)*100+j-i*(i-1)/2][krec]=1;
dp2[(i-1)*100+j-i*(i-1)/2][j]=1;
}
}
}
for(int i=1;i<=len;i++){
if(dp2[len][i]==1){
cout<<s[i];
}
else{
if(s[i]=='('||s[i]==')'){
cout<<'('<<')';
}
else{
cout<<'['<<']';
}
}
}
}