zoukankan      html  css  js  c++  java
  • 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.

    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]的次序也是最优的。动态规划算法解此问题,可依据其递归式以自底向上的方式进行计算.(更为详细可见算法导论)

    状态转移方程: 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
    ",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
    ",dp[1][len]);
        print_path(1,len);
        printf("
    ");
        return 0;
    }
  • 相关阅读:
    浅谈MSSQL2012中的列存储索引(columnstore indexes)
    《高性能SQL调优精要与案例解析》新书样章
    关系库执行计划中三种最常用连接方式的伪码实现
    python基础-字符串
    python基础-文件和目录
    python基础-列表
    python基础-对象
    python基础-入门
    python算法-二叉树广度优先遍历
    Python算法-二叉树深度优先遍历
  • 原文地址:https://www.cnblogs.com/liyinggang/p/5374629.html
Copyright © 2011-2022 走看看