# 动态规划 POJ1141 Brackets Sequence 解题报告

Description

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

()[()]

Source

Northeastern Europe 2001
题目意思就是说给一个不规则的字符串，求添加最少的字符使其成为一个规则的字符串。规则的字符串题目中已经给出了定义。本题在LRJ的书上是作为dp的第一个例题讲的，看起来十分简单，其实我感觉对于dp初学者来说，难度还是很大的。LRJ的书上虽然给出了解题的思路，却没有给出完整的答案，只是通过这个题告诉你什么是dp。本题的解法就是通过求序列s[i][i+1]...s[j]最少需要添加的括号d[i][j]来求最终的字符串。但是书上讲得非常模糊，甚至在113页的代码还有一点小错误，所以并不十分易懂。甚至会给初学者造成困扰。
本人的想法如下：
对于任何s[i]..s[j]应该分为两种情况考虑，一种是s[i]='('&&s[j]=')' 或者s[i]='['&&s[j]=']'，如果是这种情况，则d[i][j]=d[i+1][j-1]，则i,j处不需要添加括号。做一标记v[i][j]=-1;即可。还有一种情况就是上述条件不满足，则可以把s[i]..s[j]分成两段考虑，枚举i,j中间的点k,i=<k<j;即可。然后取d[i][j]=min(d[i][j],d[i][k]+d[k+1][j]);同时应该对所取得k进行标记v[i][j]=k。
然后就是输出问题，对任意的s[i]..s[j]，对其输出，如果i>j则输出结束。否则分几种情况考虑：1.i=j;则此时i,j指的就是一个单个字符，如果s[i]='('or')'直接输出一对括号即可。等于'['同上。但是一般的情况都是i,j中间还有字符，要分两种情况，如果v[i][j]=-1;即标记时s[i]、s[j]是一对，此时输出s[i],s[i+1]..s[j-1],s[j]即可。如果更一般的情况即v[i][j]不等于-1的时候就是说s[i]..s[j]已经在i,j中间分开，那么仍然是递归输出s[i]...s[v[i][j]],s[v[i][j]+1]...s[j]即可。至此输出完成。
以上仅为个人的一点看法。dp是算法里面最难掌握的部分之一，需要大量的练习。
#include<iostream>
#include<string>
#include<fstream>
using namespace std;
string s;
int d, value, length;
void fun()
{
for (int p = 0; p < length; p++)d[p][p] = 1;
for (int tem = 1; tem < length; tem++)
for (int i = 0; i < length - tem; i++)
{
int j = tem + i;
d[i][j] = 99999;
if ((s[i] == '(' && s[j] == ')') || (s[i] == '[' && s[j] == ']'))//1@
{
d[i][j] = d[i + 1][j - 1];
value[i][j] = -1;
}
for (int k = i; k < j; k++)//此处需要注意，即便1@处成立，也不能省略
if (d[i][j] > d[i][k] + d[k + 1][j])
{
d[i][j] = d[i][k] + d[k + 1][j];
value[i][j] = k;
}
}
return;
}
void print(int i, int j)
{
if (i > j)return;
else if (i == j)
{
if (s[i] == '(' || s[i] == ')')	printf("()");
if (s[i] == '[' || s[i] == ']')printf("[]");
}else if (value[i][j] == -1)
{
printf("%c", s[i]);
print(i + 1, j - 1);
printf("%c", s[j]);
}else {
print(i, value[i][j]);
print(value[i][j] + 1, j);
}
return;
}
int main()
{
while (getline(cin, s))
{
memset(d, 0, sizeof(d));
length = (int)s.length();
fun();
print(0, length - 1);
printf("\n");
}
return 0;
}

posted @ 2011-02-12 16:31 like@neu 阅读(...) 评论(...) 编辑 收藏