动态规划 POJ1141 Brackets Sequence 解题报告
原题链接:http://poj.org/problem?id=1141
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.
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[101][101], value[101][101], 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; }