Let us define a regular brackets sequence in the following way:
1. Empty sequence is a regular sequence.
2. If S is a regular sequence, then (S) and [S] are both regular sequences.
3. If A and B are regular sequences, then AB is a regular sequence.
For example, all of the following sequences of characters are regular brackets sequences:
(), [], (()), ([]), ()[], ()[()]
And all of the following character sequences are not:
(, [, ), )(, ([)], ([(]
Some sequence of characters '(', ')', '[', and ']' is given. You are to find the shortest possible regular brackets sequence, that contains the given character sequence as a subsequence. Here, a string a1 a2 ... an is called a subsequence of the string b1 b2 ... bm, if there exist such indices 1 = i1 < i2 < ... < in = m, that aj = bij for all 1 = j = n.
Input
The input file contains at most 100 brackets (characters '(', ')', '[' and ']') that are situated on a single line without any other characters among them.
Output
Write to the output file a single line that contains some regular brackets sequence that has the minimal possible length and contains the given sequence as a subsequence.
Sample Input
([(]
Sample Output
()[()]
题意:输入一个字符串,输出添加最少符号满足合法的字符串。
思路:
本题是区间dp(一般想法是区间从小到大求值、记忆化搜索)
dp[i][j]:区间[i,j]合法所添加的最少个数。
有以下两种情况:
1、若s[i]、s[j]相匹配,那么
dp[i][j]=min(dp[i][j],dp[i+1][j-1]);
2、区间[i,j]间断点k (i<=k<j)
dp[i][j]=min(dp[i][j],dp[i+1][j-1]);
最终的值就是上述两种情况综合起来。
此题还需要打印路径,再用一个数组pah[i][j]记录是有上述哪一种情况转移过来的,递归输出即可。
#include <iostream>
#include<cstring>
#include<stdio.h>
using namespace std;
const int N=105;
int dp[N][N],n,path[N][N];
char s[N];
void print(int i ,int j){
if(i>j) return;
if(i==j){//当有一个字符时直接输出成对符号
if(s[i]=='('||s[i]==')'){
cout<<"()";
}
else{
cout<<"[]";
}
}
else if(path[i][j]==-1){//首尾像匹配情况
cout<<s[i];
print(i+1,j-1);
cout<<s[j];
}
else{
print(i,path[i][j]);//间断点情况
print(path[i][j]+1,j);
}
}
int main()
{
while(gets(s)){
n=strlen(s);
if(n==0){//注意有空行的情况
cout<<endl;
continue;
}
for(int i=0; i<n; i++){//长度是1
dp[i][i]=1;
}
for(int len=2; len<=n; len++){//长度从2开始,区间由小到大求值,这是区间dp常用套路
for(int i=0; i<=n-len; i++){//区间开始点
int j=i+len-1;//区间终点
dp[i][j]=0x7fffffff;
if((s[i]=='('&&s[j]==')')||(s[i]=='['&&s[j]==']')){//首尾能匹配
dp[i][j]=dp[i+1][j-1];
path[i][j]=-1;//记录
}
for(int k=i;k<j; k++){//有间断点情况
if(dp[i][j]>dp[i][k]+dp[k+1][j]){
dp[i][j]=dp[i][k]+dp[k+1][j];
path[i][j]=k;
}
}
}
}
print(0,n-1);
cout<<endl;
}
return 0;
}