题目传送门
这道题有两个难点
如何找到当前区间最小的添加值
现在我们使用两个指针
i
,
j
i,j
i,j,用这个两个指针
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]来记录一下,如果
s
[
i
]
,
s
[
j
]
s[i],s[j]
s[i],s[j]是合法的一对括号序列,那么状态转移方程就是:
d
p
[
i
]
[
j
]
=
m
i
n
(
d
p
[
i
]
[
j
]
,
d
p
[
i
+
1
]
[
j
−
1
]
)
dp[i][j]=min(dp[i][j],dp[i+1][j-1])
dp[i][j]=min(dp[i][j],dp[i+1][j−1])
然而对于所有情况来说,状态转移方程其实应该是再来一个指针
k
k
k,让
k
k
k来遍历
i
,
j
i,j
i,j这个区间,那么现在我们的状态转移方程就是:
d
p
[
i
]
[
j
]
=
m
i
n
(
d
p
[
i
]
[
j
]
,
d
p
[
i
]
[
k
]
+
d
p
[
k
+
1
]
[
j
]
)
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j])
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j])
那么现在动态规划法找出最小插入数就不成问题了,那么现在的一个问题就是如何打印输出
如何打印输出
这道题我认为我做不出来的主要原因就是卡在如何打印输出,当时我有的一个想法其实是有记忆化的动态规划,类似于之前的 b f s bfs bfs可记忆的功能(其实就是开了一个 s t a c k stack stack啦),但是根据答案来说还是我多虑了,其实就是使用递归的特性,如何使用递归的特性呢?其实应该是利用我们刚刚跑出来的 d p dp dp,然后遍历一下这个整个区间,
#include<iostream>
#include<cstring>
#include<algorithm>
#include<bits/stdc++.h>
using namespace std;
int dp[105][105];
string s;
int n;
int match(int i,int j){
if(s[i]=='('&&s[j]==')')return 1;
else if(s[i]=='['&&s[j]==']')return 1;
else return 0;
}
void print(int l,int r){
if(r<l)return ;
if(l==r){
if(s[l]=='('||s[r]==')')cout<<"()";
else cout<<"[]";
return;
}
if(match(l,r)&&dp[l][r]==dp[l+1][r-1]){
cout<<s[l];
print(l+1,r-1);
cout<<s[r];
return;
}
for(int i=l;i<r;i++){
if(dp[l][r]==dp[l][i]+dp[i+1][r]){
print(l,i);
print(i+1,r);
return;
}
}
}
int main(){
int T;
cin>>T;
getchar();
while(T--){
n=0;
memset(dp,0,sizeof(dp));
getline(cin,s);
getline(cin,s);n=s.size();
s=" "+s;
for(int i=1;i<=n;i++){dp[i][i]=1;dp[i][i-1]=0;}
if(n==0){
cout<<"\n\n";
continue;
}
for(int i=n-1;i;i--){
for(int j=i+1;j<=n;j++){
dp[i][j]=n;
if(match(i,j)){
dp[i][j]=min(dp[i][j],dp[i+1][j-1]);
}
for(int k=i;k<j;k++){
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]);
}
}
}
//cout<<dp[1][4]<<" "<<dp[2][3]<<endl;
print(1,n);
puts ("");
if (T) puts ("");//格式注意一下
}
}