poj 1141 动态规划

题意:  黑书P113  括号配对

1 空序列是规则序列

2 如果S是规则序列,则(S)或[S]是规则序列

3 如果A和B是规则序列,则AB是规则序列

给定序列,要求尽可能少的添加括号使其成为规则序列,输出规则序列。

分析:设dp[i][j]为S[i~j]最少需要增加的括号数, 

dp[i, j] = ( dp[i+1, j-1], dp[i, k] + dp[k+1, j] )     (i<=k<j)

 

 

int dp[105][105],Div[105][105];
string str;

void init(){
    string temp="";         //去除空格
    int len=str.size();
    for(int i=0;i<len;i++)
        if(str[i]!=' ')
            temp+=str[i];
    str=temp;
    for(int i=0;i<104;i++)//初始化
        for(int j=i;j<105;j++){
            dp[i][j]=999999;
            Div[i][j]=0;
        }
    for(int i=0;i<104;i++){
        dp[i][i]=1;//本身需要一个配对
        dp[i+1][i]=0;//空串需要0个
    }
}

int solve(int i,int j){
    if(dp[i][j]<999999)return dp[i][j];//记忆化搜索
    for(int k=i;k<j;k++){
        int t1=solve(i,k),t2=solve(k+1,j);//从k,k+1处分开
        if(t1+t2<dp[i][j]){
            dp[i][j]=t1+t2;
            Div[i][j]=k;
        }
    }
    if(str[i]=='('&&str[j]==')'||str[i]=='['&&str[j]==']')//不分开,首尾配对
        if(dp[i][j]>dp[i+1][j-1]){
            dp[i][j]=dp[i+1][j-1];
            Div[i][j]=j;
        }
    return dp[i][j];
}

string add(int i,int j){
    if(i>j)return "";//i和i+1配对的情况
    if(i==j)//进行配对{
        if(str[i]=='('||str[i]==')')return "()";
        else if(str[i]=='['||str[i]==']')return "[]";
    }

    int t=Div[i][j];
    if(t==j) return str[i]+add(i+1,j-1)+str[j];//首尾配对,对中间部分添补
    return add(i,t)+add(t+1,j);//从t处分成两部分,分别添补
}

int main(){
    getline(cin,str);
    init();
    solve(0,str.size()-1);
    cout<<add(0,str.size()-1)<<endl;
    return 0;
}

 

 

posted @ 2013-06-18 13:44  心向往之  阅读(145)  评论(0编辑  收藏  举报