URAL 1183 Brackets Sequence DP 路径输出

题意:长度小于100的字符串s只由四种字符"()[]"组成,求以该串为子串的最短的合法串。合法串递归定义为:

(1)空串合法

(2)如果S合法,则(S)、[S]合法

(3)如果A、B合法,则AB合法

思路:

设dp[i][j]为s(i,j)变为合法串后,合法串的长度或需要添加的字符的个数,状态转移:

(1)如果s[i]和s[j]匹配,dp[i,j]=dp[i+1,j-1]。

(2)如果不匹配,划分s(i,j)为s(i,k)和s(k+1,j),划分后dp[i,j]=dp[i,k]+dp[k+1,j],如果两个子串匹配的括号数最多,那么需要添加的字符比较最少,即dp[i,k+1]+dp[k+1,j]最小,k类似分段点,s(i,k)和s(k+1,j)可以分别输出,所以dp[i,j]=min(dp[i,k]+dp[k+1,j])

 

依赖关系:

求dp[i,j]要先求[i,k][k,j],即大区间依赖于小区间,所以要从区间长度最小的开始遍历。要把小区间全部遍历完,就从0开始遍历起点。所以有

 for len = 2 to n
    for start = 0 to n-1
      状态转移,遍历k

 

初始状态:

dp[i][i]一定需要匹配一个字符,所以dp[i,i]=1

 

输出

如果知道s中哪个是不能在s中匹配的,在该字符旁边加一个匹配的就可以了。s[i,j]需要dp[i,j]个字符匹配,分情况讨论情况:

如果i>j,非法区间

如果i==j,单个字符,直接输出对应的"()"或者"[]"

如果i<j,合法区间,分情况

如果s[i]和s[j]匹配,只需看s(i+1,j-1)看,递归输出 output(s[i]); output(i+1,j-1); output(j);

如果s[i]和s[j]匹配不匹配,在dp[i,k]在状态转移时分段点k是唯一的,(i,k)和(k+1,j)是独立的,所以可以用一个pos[i,j]记录下k,然后分段输出,即output(i,k); output(k+1,j)

算法步骤:

步骤1:初始化dp[][]为无穷大,dp[i][i]=1,pos=-1。

步骤2:递推求dp[i][j],然后根据pos递归输出新串。

代码:

int dp[110][110],pos[110][110];
void DFSprint(int l,int r)   // 路径输出
{
     if(l>r) return ;
     if(l==r){
         if(s[l]==‘(‘||s[l]==‘)‘) cout << "()" ;
         else cout << "[]" ;
     }
     else if(pos[l][r]==-1){
         cout << s[l]; DFSprint(l+1,r-1); cout << s[r];
     }
     else{
          DFSprint(l,pos[l][r]);  DFSprint(pos[l][r]+1,r);
     }
}
int main()
{
    cin >> s ;
    memset(dp,inf,sizeof(dp));
    memset(pos,-1,sizeof(pos));
int len = s.size();

for(int i=0;i<len;++i)
dp[i][i]=1,dp[i+1][i]=0;

    for(int length=1; length<len; ++lenght){
        for(int start=0; start+length<len; ++start){
            dp[i][j]=len+1; // max
            // s[i] s[j] 匹配
if( (s[i]==‘(‘&&s[j]==‘)‘) || (s[i]==‘[‘&&s[j]==‘]‘))
                dp[i][j]=min(dp[i][j], dp[i+1][j-1]);
            // 状态转移
            for(int k=i;k<j;++k){
                if(dp[i][j] > dp[i][k]+dp[k+1][j]){
                    dp[i][j] =  dp[i][k]+dp[k+1][j];
                    pos[i][j] = k;
                }
            }
        }
    }
    DFSprint(0,len-1);
    cout << endl;
    return 0;
}
 
时间: 2024-10-11 23:06:39

URAL 1183 Brackets Sequence DP 路径输出的相关文章

记忆化搜索+DFS URAL 1183 Brackets Sequence

题目传送门 1 /* 2 记忆化搜索+DFS:dp[i][j] 表示第i到第j个字符,最少要加多少个括号 3 dp[x][x] = 1 一定要加一个括号:dp[x][y] = 0, x > y; 4 当s[x] 与 s[y] 匹配,则搜索 (x+1, y-1); 否则在x~y-1枚举找到相匹配的括号,更新最小值 5 */ 6 #include <cstdio> 7 #include <algorithm> 8 #include <cmath> 9 #include

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

题目地址:Ural 1183 最终把这题给A了.. .拖拉了好长时间,.. 自己想还是想不出来,正好紫书上有这题. d[i][j]为输入序列从下标i到下标j最少须要加多少括号才干成为合法序列.0<=i<=j<len (len为输入序列的长度). c[i][j]为输入序列从下标i到下标j的断开位置.假设没有断开则为-1. 当i==j时.d[i][j]为1 当s[i]=='(' && s[j]==')' 或者 s[i]=='[' && s[j]==']'时,d

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

(review)zoj1276 区间dp+路径输出

[题解]:经典的区间dp,并且记录下了dp的path 因为是递归得到的path,所以递归压栈按从里到外的顺序得到path就可以了 输出嵌套括号部分很好的考察了对栈的理解,和递归执行的顺序. 注意题目输出中有的地方有空格 1 //zoj1276 路径输出用到了栈的思想,比较考验思维 2 #include<iostream> 3 #include<string.h> 4 #include<stdio.h> 5 #define maxn 13 6 using namespac

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 regu

ural Brackets Sequence (dp)

http://acm.timus.ru/problem.aspx?space=1&num=1183 很经典的问题吧,看的黑书上的讲解. 设dp[i][j]表示i到j括号合法需要的最少括号数. 共有四种情况: s[i]s[j]配对,dp[i][j] = min( dp[i][j] ,  dp[i-1][j+1] ): s[i] = '('或'[' dp[i][j] = min( dp[i][j] , dp[i+1][j]+1 ): s[j] = ')'或']' dp[i][j] = min( dp

ural Binary Lexicographic Sequence (dp + dfs)

http://acm.timus.ru/problem.aspx?space=1&num=1081 有一个二进制序列,定义为不能有两个连续的1出现,才是合法的.给出序列的长度n,求合法的二进制序列中按字典序排序后第k个序列是什么. 设dp[i][0]和dp[i][1]分别表示第i位上是0和1的个数. 那么dp[i][0] = dp[i-1][0] + dp[i-1][1]:dp[i][1] = dp[i-1][0],打表发现和斐波那契数列相似. 求第k个合法的序列时,因为是按字典序排序,可以发现

选课 树形dp+路径输出

#include<iostream> #include<cstdio> #include<cstring> #define maxn 2010 using namespace std; int n,m,v[maxn],sum[maxn],son[maxn][maxn],s[maxn][3],f[maxn][maxn]; bool falg[maxn]; int Dfs(int k,int p) { if(k==0&&p!=m||p==0)return 0

POJ 1141 Brackets Sequence (区间dp 记录路径)

题目大意: 给出一种不合法的括号序列,要求构造出一种合法的序列,使得填充的括号最少. 思路分析: 如果只要求输出最少的匹配括号的数量,那么就是简单的区间dp dp[i][j]表示 i - j 之间已经合法了最少添加的括号数. 转移 就是 dp[i] [j] = min  (dp[i+1][j]+1 , dp[ i+ 1] [ k -1 ] + dp[k+1] [j] (i k 位置的括号匹配)) 其次我们要记录路径,你发现  如果 dp [i] [j] 是由 dp [i+1] [j] 转移过来的