zoukankan      html  css  js  c++  java
  • 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;
    }
     
  • 相关阅读:
    clientHeight和offsetHeight
    bus事件总线传值
    解决英文溢出不换行
    小程序熏染可滑动动态导航
    个人样式小结
    数组删除元素
    vue封装swiper
    大佬的接口玩玩
    Java探针技术-JVM的动态agent机制:在main函数启动之后运行agent
    Java探针技术-Instrumentation与ClassFileTransformer--字节码转换工具
  • 原文地址:https://www.cnblogs.com/tinyork/p/5044047.html
Copyright © 2011-2022 走看看