题目
poj1141
题意:
给出字符串,求使其成为常规字符串的最短字符串
例如,以下所有字符序列都是常规方括号序列:
(),[],(()),([]),()[],()[()]
并且以下所有字符序列都不是:
(,[,),)(,([)],([(]
思路:
dp数组是记录区间 [ i , j ] 成为常规字符串的最短次数。
在区间 [ i , j ] 内,
如果a [ i ] = ‘(’ 并且a [ j ] = ‘)’(或a [ i ] = ‘[’ 并且a [ j ] = ‘]’ ),则
d
p
[
i
]
[
j
]
=
m
i
n
(
min
k
=
i
j
−
1
d
p
[
i
]
[
k
]
+
d
p
[
k
+
1
]
[
j
]
,
d
p
[
i
+
1
]
[
j
−
1
]
)
dp[i][j]=min(\min_{k=i}^{j-1}dp[i][k]+dp[k+1][j], dp[i+1][j-1])
dp[i][j]=min(k=iminj−1dp[i][k]+dp[k+1][j],dp[i+1][j−1])
否则,
d
p
[
i
]
[
j
]
=
min
k
=
i
j
−
1
d
p
[
i
]
[
k
]
+
d
p
[
k
+
1
]
[
j
]
dp[i][j]=\min_{k=i}^{j-1}dp[i][k]+dp[k+1][j]
dp[i][j]=k=iminj−1dp[i][k]+dp[k+1][j]
并记录每个区间 [ i , j ] 的切点 k(如果没有就不用记录)
在区间 [ i , j ] 成为常规字符串的一种方法是在要更改的字符的位置更改。
as:([)]),在第三个字符 ’ ( ’ 处把 ’ ( ’ 改成 “ () ”。
从dp [ 0 , len - 1 ] dfs:
如果在区间 [ i , j ] 没有切点 k,则打印a[i] + 区间 [ i+1 , j-1 ] + a[j];
如果在区间 [ i , j ] 有切点 k,则打印区间 [ i , k ] + 区间 [ k+1 , j ];
如果在区间 [ i , j ] 内i = j,则打印 “ () ” 或 “ [] ”;
代码
#include <iostream>
#include <algorithm>
#include <cstring>
#define DEBUG freopen("_in.txt", "r", stdin); freopen("_out1.txt", "w", stdout);
using namespace std;
const int MAXN = 110;
const int INF = 1e9;
char a[MAXN], b[MAXN], t[] = "([])"; //a:输入的字符串,b:字符串每个字符对应的更改字符
bool ac[MAXN]; //是否要更改
int dp[MAXN][MAXN], path[MAXN][MAXN], need[200]; //dp:记录最少次数,path:记录切点k位置,need:"([])"在t[]中对应的坐标
void dfs(int l, int r){
if (l > r)
return;
if (l == r)
ac[l] = true;
else if (path[l][r] == -1)
dfs(l+1, r-1);
else{
dfs(l, path[l][r]);
dfs(path[l][r]+1, r);
}
}
void solve(){
int lena = strlen(a);
memset(path, -1, sizeof(path));
for (int i = 0; i < lena; i++) //记录字符串每个字符对应的更改字符
b[i] = t[need[a[i]]];
for (int i = 0; i < lena; i++)
dp[i][i] = 1;
for (int len = 1; len < lena; len++)
for (int i = 0; i < lena - len; i++){
int j = i + len;
dp[i][j] = INF;
if (a[i] == b[j] && a[i] < a[j]) //()和[]
dp[i][j] = dp[i+1][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;
}
}
dfs(0, lena-1);
for (int i = 0; i < lena; i++)
if (ac[i])
printf("%c%c", min(a[i],b[i]), max(a[i],b[i]));
else
printf("%c", a[i]);
printf("\n");
}
int main(){
for (int i = 0; i < 4; i++)
need[t[i]] = 3 - i;
scanf("%s", a);
solve();
return 0;
}