今天很高兴,十几个清华本科和30个左右985专业第一,经过三天的角逐,终于让我拿到了清深的offer,夏令营的第一个收获!可以安心的九推冲击清软了
给一些括号,求让它们合法最少要加上多少括号,并输出加上后的结果,合法的定义:
1.空串是合法的
2.若S是合法的,则[S]和(S)均是合法的
3.若A和B是合法的,则AB是合法的
一道类似的区间dp问题,区间dp问题写的不多,右边这道回文子串算是一个,但是自己思维却是被这道题固化了,遇到最小括号匹配时也想用相同的dp方法来作,先附上我第一遍的代码:
#define inf 0x3f3f3f3f
#define ll long long
#define vec vector
#define P pair
#define MAX 105
string ds[MAX][MAX], s;
int dp[MAX][MAX];
map<char, char> ma;
int main() {
ma['['] = ']', ma[']'] = '[', ma['('] = ')', ma[')'] = '(';
while (cin >> s) {
memset(dp, 0, sizeof(dp));
int len = s.size();
for (int i = 0; i < len; i++) {
dp[i][i] = 1;
for (int j = 0; j < len; j++) {
ds[i][j] = "";
}
if (s[i] == '(' || s[i] == '[')ds[i][i] += s[i], ds[i][i] += ma[s[i]];
else ds[i][i] += ma[s[i]], ds[i][i] += s[i];
}
for (int k = 2; k <= len; k++) {//枚举长度
for (int beg = 0; beg + k - 1 < len; beg++) {//枚举起点
int i = beg, j = beg + k - 1;
//是左侧的符号,而且可以匹配
if ((s[i] == '(' || s[i] == '[') && ma[s[i]] == s[j])
dp[i][j] = dp[i + 1][j - 1], ds[i][j] = s[i] + ds[i + 1][j - 1] + s[j];
else {
if (dp[i + 1][j] <= dp[i][j - 1]) {
dp[i][j] = dp[i + 1][j] + 1;
if (s[i] == '(' || s[i] == '[')
ds[i][j] += s[i], ds[i][j] += ma[s[i]] + ds[i + 1][j];
else
ds[i][j] + ma[s[i]], ds[i][j] += s[i] + ds[i + 1][j];
}
else {
dp[i][j] = dp[i][j - 1] + 1;
ds[i][j] += ds[i][j - 1];
if (s[i] == '(' || s[i] == ']')
ds[i][j] += s[i], ds[i][j] += ma[s[i]];
else
ds[i][j] += ma[s[i]], ds[i][j] += s[i];
}
}
}
}
cout << ds[0][len - 1] << endl;
}
}
这个代码使用了判断最少添加元素组成回文串的一种简单思路,
dp[i][j]=dp[i-1][j+1]
,否则要么在左侧加个元素和区间右端匹配,要么在右侧加个元素和区间左侧匹配,于是我就写出了上面的代码,但是需要注意的是,这里可能有()[()]
这种形式,用上面的代码写出来结果却是不对的,因为左右端点( ]
不相等,因此会找 d p [ i + 1 ] [ j ] dp[i+1][j] dp[i+1][j]和 d p [ i ] [ j − 1 ] dp[i][j-1] dp[i][j−1]中最小的。
显然这道题我们不能单纯的拿端点说事,那么我们如何找到最少添加的符号数?值得注意的是,我们如果在左右端点之间中任意找一点,他的左侧组成合法串需要添加的符号数+右侧组成合法串需要添加的符号数最小的话,我们就找到了结果,所以递推关系式是这样的:
i ≤ k < j , d p [ i ] [ j ] = m i n ( d p [ i ] [ k ] , d p [ k + 1 ] [ j ] ) i \leq k < j,dp[i][j] = min(dp[i][k],dp[k + 1][j]) i≤k<j,dp[i][j]=min(dp[i][k],dp[k+1][j])
不要被自己的经验误导!多思考
//1040K 282MS
#define inf 0x3f3f3f3f
#define ll long long
#define vec vector
#define P pair
#define MAX 105
string ds[MAX][MAX], s;
int dp[MAX][MAX];
map<char, char> ma;
int main() {
ma['['] = ']', ma[']'] = '[', ma['('] = ')', ma[')'] = '(';
getline(cin, s);
if (s == "") { cout << endl; return 0; }
memset(dp, 0, sizeof(dp));
int len = s.size();
for (int i = 0; i < len; i++) {
dp[i][i] = 1;
for (int j = 0; j < len; j++) {
ds[i][j] = "";
}
if (s[i] == '(' || s[i] == '[')ds[i][i] += s[i], ds[i][i] += ma[s[i]];
else ds[i][i] += ma[s[i]], ds[i][i] += s[i];
}
for (int k = 2; k <= len; k++) {//枚举长度
for (int beg = 0; beg + k - 1 < len; beg++) {//枚举起点
int i = beg, j = beg + k - 1;
dp[i][j] = inf;
//先考虑两边为端点可不可以
if ((s[i] == '(' || s[i] == '[') && ma[s[i]] == s[j])
dp[i][j] = dp[i + 1][j - 1], ds[i][j] = s[i], ds[i][j] += ds[i + 1][j - 1] + s[j];
for (int t = i; t < j; t++) {
if (dp[i][t] + dp[t + 1][j] < dp[i][j]) {
dp[i][j] = dp[i][t] + dp[t + 1][j];
ds[i][j] = ds[i][t] + ds[t + 1][j];
}
}
}
}
cout << ds[0][len - 1] << endl;
}