1626 - Brackets sequence(DP)

和前面一样,要注意状态的枚举顺序,边界是d[i+1][i] = 0 和d[i][i] = 1  ,所以枚举的区间应该从小到大,大区间依赖于小区间的最优解 。

然后就是状态的转移,是如何转移的呢? d[i][j]表示字符串i~j的最优解,那么先检查i与j是否匹配,如果匹配,状态转移可以转移到d[i+1][j-1] 。 无论是否匹配,状态还都能转移到子区间上:d[i][k] 和 d[k+1][j] ,这是不是就像最优矩阵链乘问题了?  只不过该题对正规括号序列的定义有一条:如果S是正规括号序列,那么(S)和[S]也都是正规括号序列,所以才有了那个多加的一条dp 。

该题的难点还在于解的打印和输入输出的格式控制(空序列陷阱) 。 细节参见代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 109;
int T,n,d[maxn][maxn];
string s;
bool match(char a,char b) {
    if((a=='('&&b==')')||(a=='['&&b==']')) return true;
    else return false;
}
void print(int i,int j) {
    if(i > j) return ;
    if(i == j) {
        if(s[i] == '(' || s[i] == ')') printf("()"); //非正规序列,补充成正规序列
        else printf("[]");    return ;
    }
    int ans = d[i][j] ;
    if(match(s[i],s[j]) && ans == d[i+1][j-1]) { //ans == d[i+1][j-1] 这个条件极其重要,只有满足这点,才能说明其依赖的子最优解是什么
        printf("%c",s[i]); print(i+1,j-1) ; printf("%c",s[j]); return ;
    }
    for(int k=i;k<j;k++) {
        if(ans == d[i][k] + d[k+1][j]) {//逐步回调寻找,寻找最优解所依赖的子最优解
            print(i,k); print(k+1,j);
            return ;
        }
    }
}
int main() {
    scanf("%d",&T);
    int c = getchar();
    c = getchar();
    while(T--) {
        getline(cin,s);
        n = s.size();
        if(n == 0) ;
        else {
            for(int i=0;i<n;i++) {
                d[i][i] = 1; d[i+1][i] = 0;
            }
            for(int i=n-2;i>=0;i--) {
                for(int j=i+1;j<n;j++) {
                    d[i][j] = n;
                    if(match(s[i],s[j])) d[i][j] = min(d[i][j],d[i+1][j-1]);
                    for(int k=i;k<j;k++) d[i][j] = min(d[i][j],d[i][k]+d[k+1][j]);
                }
            }
            print(0,n-1);
        }   printf("\n");            //格式控制
        if(T) printf("\n");
        if(T) c = getchar();
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-05 12:41:01

1626 - Brackets sequence(DP)的相关文章

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

URAL 1183 Brackets Sequence(DP)

题目链接 题意 : 给你一串由括号组成的串,让你添加最少的括号使该串匹配. 思路 : 黑书上的DP.dp[i][j] = min{dp[i+1][j-1] (sh[i] == sh[j]),dp[i][k]+dp[k+1][j](i<=k<j)}.输出的时候递归,其实我觉得输出比dp部分难多了..... 1 #include <stdio.h> 2 #include <string.h> 3 #include <iostream> 4 5 using nam

POJ1141 Brackets Sequence (dp动态规划,递归)

本文出自:http://blog.csdn.net/svitter 原题:http://poj.org/problem?id=1141 题意:输出添加括号最少,并且使其匹配的串. 题解: dp [ i ] [ j ] 表示添加括号的个数, pos[ i][ j ] 表示 i , j 中哪个位置分开,使得两部分分别匹配. pos [ i ][ j ] 为-1的时候,说明i, j 括号匹配. 初始值置dp [ i ] [ i ]  = 1; 如果只有一个括号,那么匹配结果必然是差1. 首先判断括号是

HDU 4908 (杭电 BC #3 1002题)BestCoder Sequence(DP)

题目地址:HDU 4908 这个题是从m开始,分别往前DP和往后DP,如果比m大,就比前面+1,反之-1.这样的话,为0的点就可以与m这个数匹配成一个子串,然后左边和右边的相反数的也可以互相匹配成一个子串,然后互相的乘积最后再加上就行了.因为加入最终两边的互相匹配了,那就说明左右两边一定是偶数个,加上m就一定是奇数个,这奇数个的问题就不用担心了. 代码如下: #include <iostream> #include <stdio.h> #include <string.h&g

[LeetCode] Longest Consecutive Sequence(DP)

Given an unsorted array of integers, find the length of the longest consecutive elements sequence. For example,Given [100, 4, 200, 1, 3, 2], The longest consecutive elements sequence is [1, 2, 3, 4]. Return its length: 4. Your algorithm should run in

AYITACM2016省赛第三周I - Optimal Array Multiplication Sequence(dp)

矩阵最少乘法 题意: 给你2个矩阵A.B,我们使用标准的矩阵相乘定义C=AB如下: A阵列中栏(column)的数目一定要等于B阵列中列(row)的数目才可以做此2阵列的相乘.若我们以rows(A),columns(A)分别代表A阵列中列及栏的数目,要计算C阵列共需要的乘法的数目为:rows(A)*columns(B)*columns(A).例如:A阵列是一个10x20的矩阵,B阵列是个20x15的矩阵,那么要算出C阵列需要做10*15*20,也就是3000次乘法. 要计算超过2个以上的矩阵相乘

Ural 1081 Binary Lexicographic Sequence(DP)

题目地址:Ural 1081 先用dp求出每个长度下的合法序列(开头为1)的个数.然后求前缀和.会发现正好是一个斐波那契数列.然后每次判断是否大于此时长度下的最少个数,若大于,说明这一位肯定是1,若小于,则肯定是0.就这样不断输出出来即可. 代码如下: #include <iostream> #include <cstdio> #include <string> #include <cstring> #include <stdlib.h> #in

cf13C Sequence(DP)

题意: N个数.a1...aN. 对于每个数而言,每一步只能加一或减一. 问最少总共需要多少步使得新序列是非递减序列. N (1 ≤ N ≤ 5000) 思路: *一个还不知道怎么证明的结论(待证):最后的新序列b1...bN中的每一个数bi,一定是原a1..aN序列中的某个数. 将a1..aN从小到大排列,得到c1...cN. dp[i][j]:原序列前i个数经过操作,第i个数不超过c[j]所花最少步数. dp[i][j]=min( dp[i-1][j]+abs(a[i]-b[j]),dp[i

Arithmetic Sequence(dp)

Arithmetic Sequence Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 51  Solved: 19[Submit][Status][Web Board] Description Giving a number sequence A with length n, you should choosingm numbers from A(ignore the order) which can form an arithmetic sequ