您的位置:首页 > 产品设计 > UI/UE

1626 - Brackets sequence(DP)

2015-07-12 16:13 344 查看
和前面一样,要注意状态的枚举顺序,边界是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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: