UVA-1626 Brackets sequence (简单区间DP)

题目大意:给一个有小括号和中括号组成的序列,满足题中的三个条件时,是合法的。不满足时是不合法的,问将一个不合法的序列最少添加几个括号可以使之变成合法的。输出最短合法序列。

题目分析:这是《入门经典》上的一道例题。如果仅让求最短序列是极简单的,定义dp(i,j)表示将区间 i~j 变为合法添加的最小字符数.

      则 dp(i,j)=dp(i+1,j-1)   (i与j能匹配时),    dp(i,j)=min(dp(i,k)+dp(k+1,j))。

但是,输出的时候就比较慢了。从左往右通过比较选择最优方案递归输出(看的书上代码)。

代码如下:

# include<iostream>
# include<cstdio>
# include<cstring>
# include<algorithm>
using namespace std;
char p[105];
int dp[105][105];
const int INF=100000;
bool match(int x,int y)
{
    if(p[x]==‘(‘&&p[y]==‘)‘)
        return true;
    if(p[x]==‘[‘&&p[y]==‘]‘)
        return true;
    return false;
}
void DP()
{
    int len=strlen(p);
    for(int l=1;l<=len;++l){
        for(int i=0;i+l-1<len;++i){
            int r=i+l-1;
            if(l==1){
                dp[i][r]=1;
                continue;
            }
            if(l==2){
                if(match(i,r))
                    dp[i][r]=0;
                else
                    dp[i][r]=2;
                continue;
            }
            dp[i][r]=INF;
            if(match(i,r))
                dp[i][r]=dp[i+1][r-1];
            for(int k=i;k<r;++k){
                dp[i][r]=min(dp[i][r],dp[i][k]+dp[k+1][r]);
            }
        }
    }
}
void print(int i,int j)
{
    if(i>j)
        return ;
    if(i==j){
        if(p[i]==‘(‘||p[i]==‘)‘)
            printf("()");
        else
            printf("[]");
        return ;
    }
    int ans=dp[i][j];
    if(match(i,j)&&ans==dp[i+1][j-1]){
        printf("%c",p[i]);
        print(i+1,j-1);
        printf("%c",p[j]);
        return ;
    }
    for(int k=i;k<j;++k){
        if(ans==dp[i][k]+dp[k+1][j]){
            print(i,k);
            print(k+1,j);
            return ;
        }
    }
}
int main()
{
    int T;
    scanf("%d",&T);
    getchar();
    while(T--)
    {
        getchar();
        gets(p);
        int len=strlen(p);
        if(len>0){
            DP();
            print(0,len-1);
        }
        printf("\n");
        if(T)
            printf("\n");
    }
    return 0;
}

  

时间: 2024-10-08 01:08:04

UVA-1626 Brackets sequence (简单区间DP)的相关文章

UVa 1626 Brackets sequence (动态规划)

题意:用最少的括号将给定的字符串匹配,输出最优解.可能有空行. 思路:dp. dp[i][j]表示将区间i,j之间的字符串匹配需要的最少括号数,那么 如果区间左边是(或[,表示可以和右边的字符串匹配,枚举中间断点k,如果str[i]==str[k]则dp[i][j]=min(dp[i][j],dp[i+1][k-1]+dp[k+1][j])表示不需要加入新的括号,也可以插入新的括号则dp[i][j]=min(dp[i][j],dp[i+1][k]+dp[k+1][j]+1). 如果区间最左边字符

uva 1626 Brackets Sequence ?(动态规划)

状态表示方法:d[ i ][ j ]表示的是一条序列的开始和结束: 状态定义:d[ i ][ j ]表示字串s[ i~j ] 需要添加的数量. #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int n; char s[105]; int d[105][105]; bool match(char ch1,char ch2) { if((ch1=='['&&am

uva 10003 Cutting Sticks 简单区间dp

// uva 10003 Cutting Sticks 区间dp // 经典的区间dp // dp(i,j)表示切割小木棍i-j所需要的最小花费 // 则状态转移为dp(i,j) = min{dp(i,k) + dp(k,j) + a[j]-a[i]) // 其中k>i && k<j // a[j] - a[i] 为第一刀切割的代价 // a[0] = 0,a[n+1] = L; // dp数组初始化的时候dp[i][i+1]的值为 0,这表示 // 每一段都已经是切割了的,不

POJ 1141 Brackets Sequence (区间DP)

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

POJ 题目1141 Brackets Sequence(区间DP记录路径)

Brackets Sequence Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 27793   Accepted: 7885   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 re

poj 1141 Brackets Sequence(区间DP)

题目:http://poj.org/problem?id=1141 转载:http://blog.csdn.net/lijiecsu/article/details/7589877 定义合法的括号序列如下: 1 空序列是一个合法的序列 2 如果S是合法的序列,则(S)和[S]也是合法的序列 3 如果A和B是合法的序列,则AB也是合法的序列 例如:下面的都是合法的括号序列 (),  [],  (()),  ([]),  ()[],  ()[()] 下面的都是非法的括号序列 (,  [,  ),  

poj2955 Brackets 简单区间dp

// poj2955 简单区间dp // d[i][j]表示i到j区间所能形成的最大匹配序列 // dp[i][j] = max(dp[i][k]+dp[k+1][j]){i<k<j} // dp[i][j] = max(dp[i+1][j-1]+2) if (s[i] match s[j]) // // 记忆化搜索的时候,将dp[i][i] = 0 ,其他赋值成-1; // // 做题的时候刚开始将dp[i][j]弄成0了,结果一直tle // 最后发现有好多的状态重复计算了,所以会tle

uva live 3516 Exploring Pyramids 区间DP

// uva live 3516 Exploring Pyramids 区间DP // // 题目大意: // // 给你一个多叉树,每个节点是一个大写字母,从根节点走,按照先序遍历的 // 原则访问,不能访问则回溯,每次记录一下节点的字符,最后得到一个字符串.现 // 在给你一个字符串,问可能符合条件的多叉树的数量. // // 解题思路: // // 区间DP,我们注意到,从根节点出发,一定会再次回到根节点,那么我们可以设 // d(i,j) 是序列i到j段形成的符合条件的多叉树的数量,则

uva 10529 - Dumb Bones(概率+区间dp)

题目连接:uva 10529 - Dumb Bones 题目大意:给定n,表示要放n个骨牌,每次放下骨牌,有可能向左倒的概率为pl,向右倒的概率为pr,如果倒下,会将那一侧的骨牌全部推倒,可以选择位置先后放骨牌,问说一种放骨牌次数最少的期望是多少. 解题思路:dp[i]表示放i个骨牌需要的步数期望,维护一个最优放的位置,dp[i] = min\{ (从i-1到i的步数)} + (0到i-1的步数)} (从i-1到i的步数):dp[i?j?1]?pl+dp[j]?pr+11?pl?pr (0到i-

简单Dp----最长公共子序列,DAG最长路,简单区间DP等

/* uva 111 * 题意: * 顺序有变化的最长公共子序列: * 模板: */ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int a[100]; int mu[100]; int Dp[100][100]; int main() { int n,x; scanf("%d", &n