【算法设计与数据结构】URAL 1183.Brackets Sequence(区间dp求解)
来源:互联网 发布:中国学术论文数据库 编辑:程序博客网 时间:2024/06/06 19:12
题目链接:
http://acm.timus.ru/problem.aspx?space=1&num=1183
题目大意:
定义正规的括号序列如下:
1. 空序列是一个正规的括号序列
2. 如果S是一个正规的括号序列, 那么(S) 和[S] 也都是正规的括号序列。
3. 如果A和B是正规的括号序列, 那么AB也是一个正规的括号序列。
现给定一个括号序列A(只包含小括号和中括号,可能为空序列),求一个正规括号序列B,使得A包含于B,而且B的长度是满足条件的序列中最小的。
思路:
我们用dp[i][j]来表示包含子序列s[i…j]的最短正规括号序列需要添加的括号数,则由定义的2和3可知:
如果 s[i]与s[j]匹配,
dp[i][j] = min{dp[i][k] + dp[k+1][j], dp[i+1][j-1]},i <= k < j;
否则,
dp[i][j] = min{dp[i][k] + dp[k+1][j]},i <= k < j;
以上便是状态转移方程,不过题目要求输出结果序列,所以我们需要标记分解的位置,然后递归打印答案。这可以通过一个mark数组来实现:如果序列不可分解为两个子序列,则mark[i][j] = -1,如果在k处分解,则mark[i][j] = k。
注意,输入可能为空,所以gets来读取一行。
算法步骤:
1) 初始化边界条件:
//单个括号,必然需要添加1个括号与其匹配dp[i][i] = 1;
2) 根据状态转移方程动态规划求解:
状态转移方程中一共有3个变量:i,j,k,由分解的性质可知,长的序列依赖于短的序列,所以我们要保证短的序列先算。我们在最外层循环设置一个变量l,表示序列的长度,2 <= l <= n,则1 <= i <= n-l+1, j = i+l-1,之后对每个i,用k来遍历划分点,i <= k < j。
for (int l = 2; l <= n; l++){ for (int i = 1; i <= n-l+1 ; i++) { int j = i+l-1; dp[i][j] = INF; if (s[i-1]=='('&&s[j-1]==')' || s[i-1]=='['&&s[j-1]==']') { if (dp[i+1][j-1] < dp[i][j]) dp[i][j] = dp[i+1][j-1]; } mark[i][j] = -1; for (int k = i; k < j; k++) { if (dp[i][k]+dp[k+1][j] < dp[i][j]) { dp[i][j] = dp[i][k] + dp[k+1][j]; mark[i][j] = k; } } }}
3) 打印结果:
根据递推关系,我们可以用printAns(1, n)递归地打印出我们的结果。对于printAns(i, j)关系如下:
如果 i > j,返回;
如果i = j,打印一对括号,返回;
如果i < j,
如果序列不用划分,则打印s[i],打印printAns(i+1,j-1),再打印s[i]对应的匹配括号;
否则,打印printAns(i,k)和printAns(k+1,j),其中k为划分点。
算法复杂度:
O(n^3)
源程序:
#include <iostream>#include <cstring>#include <algorithm>#include <cstdio>using namespace std;const int INF = 99999999;char s[120];int dp[120][120];int mark[120][120];void printAns(int i, int j){ if (i > j) return; if (i == j) { if (s[i-1] == '(' || s[i-1] == ')') cout<<"()"; else cout<<"[]"; return; } if (mark[i][j] == -1) { if (s[i-1] == '(') { cout<<'('; printAns(i+1, j-1); cout<<')'; } else { cout<<'['; printAns(i+1, j-1); cout<<']'; } } else { printAns(i,mark[i][j]); printAns(mark[i][j]+1,j); }}int main(){ gets(s); int n = strlen(s); if (!n) { cout<<endl; } else { memset(dp, 0, sizeof(dp)); for (int i = 1; i <= n; i++) dp[i][i] = 1; for (int l = 2; l <= n; l++) { for (int i = 1; i <= n-l+1 ; i++) { int j = i+l-1; dp[i][j] = INF; if (s[i-1]=='('&&s[j-1]==')' || s[i-1]=='['&&s[j-1]==']') { if (dp[i+1][j-1] < dp[i][j]) dp[i][j] = dp[i+1][j-1]; } mark[i][j] = -1; for (int k = i; k < j; k++) { if (dp[i][k]+dp[k+1][j] < dp[i][j]) { dp[i][j] = dp[i][k] + dp[k+1][j]; mark[i][j] = k; } } } } printAns(1, n); cout<<endl; } return 0;}
- 【算法设计与数据结构】URAL 1183.Brackets Sequence(区间dp求解)
- 【URAL 1183】Brackets Sequence(区间DP+路径记录)
- Brackets Sequence (区间dp)
- ural Brackets Sequence (dp)
- URAL 1183.Brackets Sequence ( DP+记录路径)
- Ural 1183 Brackets Sequence(区间DP+记忆化搜索)
- POJ 1141 Brackets Sequence(区间DP)
- POJ 1141 Brackets Sequence (区间DP)
- poj 1141 Brackets Sequence(区间dp)
- poj 1141 Brackets Sequence(区间dp)
- poj1141 Brackets Sequence(区间dp)
- POJ 1141 Brackets Sequence(区间DP)
- POJ 1141 Brackets Sequence(区间DP)
- poj1141 Brackets Sequence (区间dp)
- poj1141 Brackets Sequence 区间dp
- ZOJ1463:Brackets Sequence(区间DP)
- POJ1141 Brackets Sequence 区间DP
- pku1141 Brackets Sequence 区间DP
- Spring4快速入门第二章配置bean(上)
- Java数据类型和MySql数据类型对应表
- Linux下安装gtest/gmock
- 代码重构
- 【Android】Android事件传递机制
- 【算法设计与数据结构】URAL 1183.Brackets Sequence(区间dp求解)
- c++学习(函数模板, 类模板)<2>
- Paxos
- oracle字符集
- iOS程序员的成才之路
- 64位Win7下Access提示”文件共享锁定数溢出“
- Jquery函数集锦
- Java中thread的join方法
- 关于iOS开发的一些坑