UVA1626 题解 / test

由 SunJude 发布

Solution

采用 区间 dp

对于串 $s$,$f_{l,r}$ 表示使 $[l,r]$ 区间变为正规括号序列所需添加的最少括号数量。

初始化:

$l = r$ 时,区间 $[l,r]$ 中只有一个括号,添加一个与之匹配的括号即可,故 $f_{l,r} = 1$。

$l > r$ 时,不存在这种情况,$f_{l,r} = 0$。

$l < r$ 时,由于需取最小值,故 $f_{l,r} = +\infty$。

状态转移:

当 $s_l$ 与 $s_r$ 匹配时,最外层括号已经匹配,只需对里面进行操作,故 $f_{l,r} = f_{l+1,r-1}$。

枚举断点 $k$,$f_{l,r} = \min(f_{l,r},f_{l,k}+f_{k+1,r})$。

时间复杂度 $O(n^3)$。

输出:

根据 $f$ 数组,递归推出 dp 过程,具体实现见代码。

注意输入与输出格式!!!

Code

#include<bits/stdc++.h>
using namespace std;
const int maxn = 105;
const int inf = 1e9; 
string s;
int f[maxn][maxn];
bool judge(int l,int r){
    return (s[l]=='(' && s[r]==')') || (s[l]=='[' && s[r]==']');
}
void Out(int l,int r){
    if(l > r) return ;
    if(l == r){
        if(s[l]=='(' || s[l]==')') cout<<"()";
        else cout<<"[]";
        return ;
    }
    if(f[l][r]==f[l+1][r-1] && judge(l,r)){
        cout<<s[l];
        Out(l+1,r-1);
        cout<<s[r]; 
        return ;
    }
    for(int k=l;k<r;k++){
        if(f[l][r] == f[l][k]+f[k+1][r]){
            Out(l,k);
            Out(k+1,r);
            return;
        }
    }
}
void solve(){ 
    memset(f,0,sizeof(f));
    getline(cin,s);
    getline(cin,s);
    int n = s.size(); 
    s = 'a'+s;
    for(int i=1;i<=n;i++){
        f[i][i] = 1;
        for(int j=i+1;j<=n;j++) f[i][j] = inf;
    } 
    for(int i=2;i<=n;i++){
        for(int l=1;l+i-1<=n;l++){
            int r = l+i-1;
            if(judge(l,r)) f[l][r] = f[l+1][r-1];
            for(int k=l;k<r;k++){
                f[l][r] = min(f[l][r],f[l][k]+f[k+1][r]);
            }
        }
    }
    Out(1,n);
    cout<<endl;
    return ;
}
int main(){
    int n;cin>>n;getchar();
    while(n--){
        solve();
        if(n) cout<<endl;
    }
    return 0;
} 

暂无评论

发表评论