链接:

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4501

题意:

定义如下正规括号序列(字符串):
1.空序列是正规括号序列。
2.如果S是正规括号序列,那么(S)和[S]也是正规括号序列。
3.如果A和B都是正规括号序列,那么AB也是正规括号序列。
输入一个长度不超过100的,由“(”、“)”、“[”、“]”构成的序列,添加尽量少的括号,得到一个正规序列。
如有多解,输出任意一个序列即可。

分析:

设串S至少需要增加d(S)个括号,转移如下:
1.如果S形如(S′)或者[S′],转移到d(S′)。
2.如果S至少有两个字符,则可以分成AB,转移到d(A)+d(B)。
边界是:S为空时d(S)=0,S为单字符时d(S)=1。
注意:不管S是否满足第一种,都要尝试第二种转移,否则“[][]”会转移到“][”,然后就只能加两个括号了。
设d(i,j)表示子串S[i~j]至少需要添加几个括号。
对于第一种,状态转移方程为:d(i,j) = d(i+1, j-1)。
对于第二种,状态转移方程为:d(i,j) = min{d(i, k) + d(k+1, j) | i ≤ k < j}。
可以在打印解的时候重新检查一下哪个决策最好。
最后,这题的输入输出有点坑。。。

代码:

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <algorithm>
  4. using namespace std;
  5.  
  6. const int UP = + ;
  7. char s[UP];
  8. int d[UP][UP]; // d[L][R]表示子串s[L~R]至少需要添加几个括号
  9.  
  10. bool match(char L, char R){
  11. return (L == '(' && R == ')') || (L == '[' && R == ']');
  12. }
  13.  
  14. void dynamic_programming(int len){
  15. for(int i = ; i < len; i++){
  16. d[i][i] = ;
  17. d[i+][i] = ;
  18. }
  19. for(int L = len - ; L >= ; L--){
  20. for(int R = L + ; R < len; R++){
  21. int& v = d[L][R];
  22. v = match(s[L], s[R]) ? d[L+][R-] : ;
  23. for(int M = L; M < R; M++) v = min(v, d[L][M] + d[M+][R]);
  24. }
  25. }
  26. }
  27.  
  28. void output(int L, int R){
  29. if(L > R) return;
  30. if(L == R){
  31. if(s[L] == '(' || s[L] == ')') printf("()");
  32. else printf("[]");
  33. return;
  34. }
  35. int ans = d[L][R];
  36. if(match(s[L], s[R]) && d[L+][R-] == ans){
  37. printf("%c", s[L]); output(L+, R-); printf("%c", s[R]);
  38. return;
  39. }
  40. for(int M = L; M < R; M++) if(d[L][M] + d[M+][R] == ans){
  41. output(L, M); output(M+, R);
  42. return;
  43. }
  44. }
  45.  
  46. int main(){
  47. int T;
  48. scanf("%d", &T);
  49. getchar();
  50. while(T--){
  51. gets(s); gets(s);
  52. int len = strlen(s);
  53. dynamic_programming(len);
  54. output(, len - ); printf("\n");
  55. if(T) printf("\n");
  56. }
  57. return ;
  58. }

最后,再贴一下我一开始的代码,状态的转移有点不同:当s[L]与s[M]不匹配时,d(L,M)转移到d(L+1,M)+1。

递推写法:

  1. #include <cstdio>
  2. #include <cstring>
  3.  
  4. const int UP = + ;
  5. char s[UP];
  6. int d[UP][UP], ans[UP][UP];
  7.  
  8. int diff(int L, int R){
  9. if(s[L] == '(') return s[R] != ')';
  10. if(s[L] == '[') return s[R] != ']';
  11. return ;
  12. }
  13.  
  14. void dynamic_programming(int len){
  15. for(int i = ; i < len; i++){
  16. d[i][i] = ;
  17. d[i+][i] = ;
  18. }
  19. for(int L = len - ; L >= ; L--){
  20. for(int R = L + ; R < len; R++){
  21. d[L][R] = ;
  22. for(int M = L; M <= R; M++){
  23. int f = diff(L, M);
  24. int v = f + d[L+][M-+f] + d[M+][R];
  25. if(d[L][R] > v){
  26. d[L][R] = v;
  27. ans[L][R] = M;
  28. }
  29. }
  30. }
  31. }
  32. }
  33.  
  34. void output(int L, int R){
  35. if(L > R) return;
  36. if(L == R){
  37. if(s[L] == '(' || s[L] == ')') printf("()");
  38. else printf("[]");
  39. return;
  40. }
  41. int M = ans[L][R];
  42. if(L == M){
  43. output(L, M); output(M+, R);
  44. return;
  45. }
  46. printf("%c", s[L]);
  47. if(!diff(L, M)) output(L+, M-), printf("%c", s[M]);
  48. else output(L+, M), printf("%c", s[L] == '(' ? ')' : ']');
  49. output(M+, R);
  50. }
  51.  
  52. int main(){
  53. int T;
  54. scanf("%d", &T);
  55. getchar();
  56. while(T--){
  57. gets(s); gets(s);
  58. int len = strlen(s);
  59. dynamic_programming(len);
  60. output(, len - ); printf("\n");
  61. if(T) printf("\n");
  62. }
  63. return ;
  64. }

记忆化写法(比递推写法慢几倍):

  1. #include <cstdio>
  2. #include <cstring>
  3.  
  4. const int INF = 0x3f3f3f3f;
  5. const int UP = + ;
  6. int d[UP][UP], ans[UP][UP];
  7. char s[UP];
  8.  
  9. int diff(int L, int R){
  10. if(s[L] == '(') return s[R] != ')';
  11. if(s[L] == '[') return s[R] != ']';
  12. return ;
  13. }
  14.  
  15. int dp(int L, int R){
  16. if(L > R) return ;
  17. if(L == R) return ;
  18. int& v = d[L][R];
  19. if(v != INF) return v;
  20.  
  21. for(int M = L; M <= R; M++){
  22. int f = diff(L, M);
  23. int res = f + dp(L+, M-+f) + dp(M+, R);
  24. if(v > res){
  25. v = res;
  26. ans[L][R] = M;
  27. }
  28. }
  29. return v;
  30. }
  31.  
  32. void output(int L, int R){
  33. if(L > R) return;
  34. if(L == R){
  35. if(s[L] == '(' || s[L] == ')') printf("()");
  36. else printf("[]");
  37. return;
  38. }
  39. int M = ans[L][R];
  40. if(L == M){
  41. output(L, M); output(M+, R);
  42. return;
  43. }
  44. printf("%c", s[L]);
  45. if(!diff(L, M)) output(L+, M-), printf("%c", s[M]);
  46. else output(L+, M), printf("%c", s[L] == '(' ? ')' : ']');
  47. output(M+, R);
  48. }
  49.  
  50. int main(){
  51. int T;
  52. scanf("%d", &T);
  53. getchar();
  54. while(T--){
  55. gets(s); gets(s);
  56. memset(d, INF, sizeof(d));
  57. dp(, strlen(s) - );
  58. output(, strlen(s) - );
  59. printf("\n");
  60. if(T) printf("\n");
  61. }
  62. return ;
  63. }

UVa 1626 - Brackets sequence(区间DP)的更多相关文章

  1. UVA 1626 Brackets sequence 区间DP

    题意:给定一个括号序列,将它变成匹配的括号序列,可能多种答案任意输出一组即可.注意:输入可能是空串. 思路:D[i][j]表示区间[i, j]至少需要匹配的括号数,转移方程D[i][j] = min( ...

  2. POJ 1141 Brackets Sequence(区间DP, DP打印路径)

    Description We give the following inductive definition of a “regular brackets” sequence: the empty s ...

  3. poj 1141 Brackets Sequence 区间dp,分块记录

    Brackets Sequence Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 35049   Accepted: 101 ...

  4. UVA - 1626 Brackets sequence (区间dp)

    题意:给定一个串,可能空串,或由'[',']','(',')'组成.问使其平衡所需添加最少的字符数,并打印平衡后的串. 分析:dp[i][j]表示区间(i,j)最少需添加的字符数. 1.递推. #in ...

  5. UVA 1626 Brackets sequence(括号匹配 + 区间DP)

    http://acm.hust.edu.cn/vjudge/contest/view.action?cid=105116#problem/E 题意:添加最少的括号,让每个括号都能匹配并输出 分析:dp ...

  6. UVa 1626 Brackets sequence (动态规划)

    题意:用最少的括号将给定的字符串匹配,输出最优解.可能有空行. 思路:dp. dp[i][j]表示将区间i,j之间的字符串匹配需要的最少括号数,那么 如果区间左边是(或[,表示可以和右边的字符串匹配, ...

  7. poj 1141 Brackets Sequence (区间dp)

    题目链接:http://poj.org/problem?id=1141 题解:求已知子串最短的括号完备的全序列 代码: #include<iostream> #include<cst ...

  8. Ural 1183 Brackets Sequence(区间DP+记忆化搜索)

    题目地址:Ural 1183 最终把这题给A了.. .拖拉了好长时间,.. 自己想还是想不出来,正好紫书上有这题. d[i][j]为输入序列从下标i到下标j最少须要加多少括号才干成为合法序列.0< ...

  9. poj 1141 Brackets Sequence ( 区间dp+输出方案 )

    http://blog.csdn.net/cc_again/article/details/10169643 http://blog.csdn.net/lijiecsu/article/details ...

随机推荐

  1. NPOI excel文件解析

    一.导入excel时要解析文件,我们直接用下面的帮助数来解析就可以了,开始是上使用该类的方法 private void ImportPlanPersonFromExcel(HttpContext co ...

  2. 怎样在ado.net中存取excel和word呢?

    办公软件指可以进行文字处理.表格制作.幻灯片制作.图形图像处理.简单数据库的处理等方面工作的软件.当然啦,这也包括了word.Excel以及PPT等.现在我们就一起来学习一下:怎样在ado.net中存 ...

  3. .NET的EF框架中:在应用程序配置文件中找不到名为“”的连接字符串问题

    今天在使用EF Code First框架时,当把模型都定义好了,想通过程序包管理控制台利用enable-migrations –force来生成数据库表的时候报错了,如下: 找不到连接字符串,但是我仔 ...

  4. 一、快速构建Springboot应用

    1.基本概念 Spring的出现对于企业级应用来说是一个福音,它让企业级应用开发更加地简单.但是随着Spring的不断发展,它也慢慢变得越来越重.即使apache出品的maven工具能够使得项目创建. ...

  5. Java API 之 正则表达式

    一.基本概念 在项目中我们经常性做的一件事是“匹配”字符串 比如: 1.我们要验证用户输入的手机号是否合法? 2.验证设置的密码是否符合规则? 3.或者替换指定字符串中的一些内容. 这么一看,似乎正则 ...

  6. 解决JVM内存溢出问题

    今天遇到了一个问题,当我在增加配置文件(*.xml)内容的时候,重新启动tomcat6时,控制台报错:java.lang.StackOverflowError: 即,栈溢出错误. 内存溢出,即程序运行 ...

  7. mysql 查询近几天的结果 按每天的粒度查询

    ),DATE_FORMAT(FROM_UNIXTIME(createtime), '%Y-%m-%d') as time from bskuser group by time

  8. JavaEE之HttpServletRequest

    HttpServletRequest //要下载的这个文件的类型--客户端会通过文件的MIME类型去区分类型 response.setContentType( getServletContext(). ...

  9. sass变量

    sass变量用法 1.sass变量必须以$符开头,后面紧跟着变量名 2.变量值和变量名之间就需要使用冒号(:)分隔开(就像CSS属性设置一样) 3.如果值后面加上!default则表示默认值 默认变量 ...

  10. 关于Array的操作

    使用Array创建数组 // 使用Array 构造函数 var colors = new Array(); // 预先给数组项数量 var colors = new Array(20); // 向Ar ...