POJ-1141-Brackets Sequence
这道题是区间dp~
括号匹配
题目大意:给你一个括号序列,让你构造一个长度最小的匹配的括号序列,使得给定的括号序列为构造的括号序列的子序列(注意是子序列)
文件形式读入
然后这道题用dp解决无疑了。
dp[i][j]表示第i个字符到第j个字符构成匹配的括号序列最小需要添加多少字符。
初始化部分:
dp[i + 1][i] = 0;(这个不用我说把~)
dp[i][i] = 1;单个字符最少要添加一个字符构成匹配的括号序列。
状态转移方程就是平常的区间dp思路啦~
循环:从后往前,长度从小到大
如果s[i] == s[j];
那么dp[i][j] = min(dp[i][j], dp[i + 1][j - 1]);这个地方就体现出前面为啥dp[i + 1][i]需要初始化为0的作用了。
因为如果此时j = i + 1;那么i + 1和j - 1之后就变成了交叉的情况。
如果s[i] != s[j];
那么就在这个区间找到合适的分界点维护最小值就行啦~
输出的时候递归输出噢~
如果满足s[i] == s[j];先输出s[i];递归中间一段。然后再输出s[j]:
如果不满足。我们先循环找到最适合的分界点。分别递归进去然后输出就行。
还是比较简单的~
但是我还是wa了。
因为output部分有个条件把==写成了=;
还是debug发现的。。。
代码部分:
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#define mst(a, n) memset(a, n, sizeof(a))
using namespace std;
const int N = 3e2 + 10;
string s;
int dp[N][N];
int judge(char x, char y)
{
return x == '(' && y == ')' || x == '[' && y == ']';
}
void output(int i, int j)
{
if (i > j)
{
return ;
}
else if (i == j)
{
cout << (s[i] == '(' || s[i] == ')' ? "()" : "[]");
return ;
}
else if (judge(s[i], s[j]) && dp[i][j] == dp[i + 1][j - 1])
{
cout << s[i];
output(i + 1, j - 1);
cout << s[j];
return ;
}
else
{
for (int k = i; k < j; k++)
{
if (dp[i][j] == dp[i][k] + dp[k + 1][j])
{
output(i, k);
output(k + 1, j);
return ;
}
}
}
}
int main()
{
while (getline(cin, s))
{
mst(dp, 1e9 + 10);
int n = s.size();
for (int i = 0; i < n; i++)
{
dp[i + 1][i] = 0;
dp[i][i] = 1;
}
for (int i = n - 2; i >= 0; i--)
{
for (int j = i + 1; j < n; j++)
{
dp[i][j] = n;
if (judge(s[i], s[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]);
}
}
}
output(0, n - 1);
cout << endl;
}
return 0;
}