题目链接:
题目大意:
给你一个长度不超过 100 100 且只包含 (,),[,] ( , ) , [ , ] 四种字符的字符串 s s ,添加 最少 的字符使其变成一个合法的字符串,输出这个合法的字符串。
合法字符串的定义:
-
sequence
s
e
q
u
e
n
c
e
is
i
s
a
a
sequence.
s
e
q
u
e
n
c
e
.
- If I f S S a a sequence s e q u e n c e , then t h e n (S) ( S ) and a n d [S] [ S ] are a r e both b o t h regular r e g u l a r sequences. s e q u e n c e s .
- If I f A A B B regular r e g u l a r sequences s e q u e n c e s , then t h e n AB A B is i s a a sequence s e q u e n c e .
样例:
Sample S a m p l e Input I n p u t
([(]
Sample S a m p l e Output O u t p u t
()[()]
解题思路:
这是一道 区间 dp d p (路径还原)
状态方程 : dp[i][j] d p [ i ] [ j ] 代表使 区间 (i,j) ( i , j ) 形成一个合法的字符串最少需要添加多的字符串?
path[i][j] p a t h [ i ] [ j ] 代表添加最少的字符使 区间 (i,j) ( i , j ) 形成一个合法的字符串的路径选择。
若 path[i][j] p a t h [ i ] [ j ] = = ,表示头尾。
若 path[i][j] p a t h [ i ] [ j ] = = ( k k != ) ,表示由 区间 (i,k) ( i , k ) 和 区间 ( k+1 k + 1 , j j ) 而来。
转移方程:
- 区间 可以由 区间 (i,k) ( i , k ) + 区间 (k+1,j) ( k + 1 , j ) 转移而来。
- 当 s[i] s [ i ] = s[j] s [ j ] 时,区间 (i,j) ( i , j ) 也可以由 区间 (i+1,j−1) ( i + 1 , j − 1 ) 转移而来。(需要注意的是:当 i+1=j i + 1 = j 时,直接 dp[i][j] d p [ i ] [ j ] = 0 0 ,否则会出现 的情况)
小思考:为什么最外层是枚举 区间长度,而不是直接枚举 区间端点 l,r l , r 呢?
- 答:因为我们转移的时候是从 小区间 转移到 大区间 的。
最后答案:根据 path[i][j] p a t h [ i ] [ j ] 记录的值,用递归还原路径。(详情请看代码)
AC代码:
#include<iostream> #include<cstring> #include<algorithm> #include<cstdio> using namespace std; const int maxn = 105; int dp[maxn][maxn],path[maxn][maxn]; char s[maxn]; void dfs(int l,int r){ if(l > r) return; if(l == r){ if(s[l] == '(' || s[l] == ')') cout << "()"; else cout << "[]"; return; } if(path[l][r] == -1){ cout << s[l];//先输出左端点, dfs(l + 1,r - 1);//再输出中间, cout << s[r];//最后输出右端点。 } else{ int k = path[l][r];//分两部分输出。 dfs(l,k); dfs(k + 1,r); } } int main(){ int n; while(gets(s + 1)){ n = strlen(s + 1); memset(dp,0x3f,sizeof(dp)); memset(path,0,sizeof(path)); for(int i = 1;i <= n;i++) dp[i][i] = 1;//初始化:自己当然初始化为 1,其他初始化为无穷大。 for(int len = 2;len <= n;len++){ for(int l = 1;l <= n - len + 1;l++){ int r = len + l - 1; if((s[l] == '(' && s[r] == ')') || (s[l] == '[' && s[r] == ']')){ if(dp[l + 1][r - 1] < dp[l][r]){ dp[l][r] = dp[l + 1][r - 1]; path[l][r] = -1; } else if(l + 1 == r){ dp[l][r] = 0; path[l][r] = -1; } } for(int k = l;k < r;k++){ if(dp[l][k] + dp[k + 1][r] < dp[l][r]){ dp[l][r] = dp[l][k] + dp[k + 1][r]; path[l][r] = k; } } } } dfs(1,n); cout << endl; } }