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;
}
 
原文地址:https://www.cnblogs.com/tinyork/p/5044047.html