poj 1141(区间DP)
Brackets Sequence
Time Limit: 1000MS | Memory Limit: 65536K | |||
Total Submissions: 29236 | Accepted: 8319 | Special Judge |
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
区间DP的题,,就是不会打印路径,,写这道题的题解之前先说说《算法导论》的动态规划中的一道题吧。
《算法导论》矩阵链乘
题目:给定 n 个矩阵的链<A1,A2...An> 矩阵Ai 的规模为 pi-1*pi,给定完全括号化方案,使得A1A2..An所需标量乘法次数最少.
思路:能用动态规划的一个性质就是最优子结构性质,也就是说计算A[i:j]的最优次序所包含的计算矩阵
子链A[i..k]和A[k+1..j]的次序也是最优的。动态规划算法解此问题,可依据其递归式以自底向上的方式进行计算.(更为详细可见算法导论)
题目:给定 n 个矩阵的链<A1,A2...An> 矩阵Ai 的规模为 pi-1*pi,给定完全括号化方案,使得A1A2..An所需标量乘法次数最少.
思路:能用动态规划的一个性质就是最优子结构性质,也就是说计算A[i:j]的最优次序所包含的计算矩阵
子链A[i..k]和A[k+1..j]的次序也是最优的。动态规划算法解此问题,可依据其递归式以自底向上的方式进行计算.(更为详细可见算法导论)
状态转移方程: if(i==j) dp[i][j] = 0 ; if(i<j) dp[i][j] = min(dp[i][j],dp[i][k]+dp[k+1][j]+pi-1*pk*pj)
#include<string.h> #include<stdio.h> #include <iostream> using namespace std; #define N 50 int dp[N][N]; ///dp[i][j] 代表 AiAi+1...Aj相乘的最小代价; int p[N]; /// Ai 矩阵的规模为 pi-1*pi ,两个相邻矩阵的相乘规模为 pi-1*pi*pi+1 int s[N][N]; ///记录 Ai - Aj中的最优分割点 void print_path(int i,int j){ if(i==j) { printf("A%d",i); }else{ printf("("); print_path(i,s[i][j]); print_path(s[i][j]+1,j); printf(")"); } } int main() { int n; scanf("%d",&n); for(int i=0;i<=n;i++){ scanf("%d",&p[i]); } for(int i=1;i<=n;i++) dp[i][i]=0; for(int l=2;l<=n;l++){ ///枚举长度 for(int i=1;i<=n-l+1;i++){ ///枚举起点 int j = i+l-1; ///终点 dp[i][j]=0xfffffff; for(int k = i;k<j;k++){ ///枚举决策点k if(dp[i][j]>dp[i][k]+dp[k+1][j]+p[i-1]*p[k]*p[j]){ dp[i][j]=dp[i][k]+dp[k+1][j]+p[i-1]*p[k]*p[j]; s[i][j] = k; } } } } printf("%d\n",dp[1][n]); print_path(1,n); } ///test: 6 /// 30 35 15 5 10 20 25 结果为 15125次
了解了矩阵链乘,接下来这道题的思想就和矩阵链乘一样了。
状态转移方程: if(i==j) dp[i][j]=1;
if(i<j) if(str[i]与str[j]匹配) dp[i][j] = dp[i+1][j-1]
else dp[i][j] = min(dp[i][j],dp[i][k]+dp[k+1][j]); k为断开的位置(决策点)
这题很坑,,用EOF结束死活过不了,看了一下Discuss区去掉EOF就AC
#include<string.h> #include<stdio.h> #include <iostream> using namespace std; #define N 105 char str[N]; int dp[N][N]; ///代表i-j区间最少添加的括号数 int s[N][N]; ///当i>j时,直接返回,不需要输出 ///当i==j时,s[i][j]为1,至少要加一个括号,如果str[i]为'(' 或者')',输出"()",否则输出"[]" ///当i<j时,如果s[i][j]>=0,说明从i到j断开了,则递归调用print_path(i, s[i][j])和print_path(s[i][j]+1, j); ///如果s[i][j]==-1,说明没有断开,如果 则输出str[i],print_path(i+1, j-1); 和str[j] void print_path(int i,int j) { if(i>j) return ; else if(i==j) { if(str[i]=='('||str[i]==')') printf("()"); else printf("[]"); } else { if(s[i][j]==-1) { printf("%c",str[i]); print_path(i+1,j-1); printf("%c",str[j]); } else { print_path(i,s[i][j]); print_path(s[i][j]+1,j); } } } int main() { scanf("%s",str+1); ///输入str+1 让字符串第0位为空,输入串占第 1-len位 int len = strlen(str+1); for(int i=1; i<=len; i++) dp[i][i]=1; for(int l = 2; l<=len; l++) { for(int i=1; i<=len-l+1; i++) { int j = i+l-1; if((str[i]=='('&&str[j]==')')||(str[i]=='['&&str[j]==']')) { dp[i][j] = dp[i+1][j-1]; s[i][j] = -1; } else dp[i][j]=0x7ffffff; for(int k=i; k<j; k++) ///寻找决策点 i<=k<j { if(dp[i][j]>dp[i][k]+dp[k+1][j]) { dp[i][j] = dp[i][k]+dp[k+1][j]; s[i][j] = k; } } } } //printf("%d\n",dp[1][len]); print_path(1,len); printf("\n"); return 0; }