poj 1141 Brackets Sequence 【區間DP+路徑記錄】

題意:

給你一個只包括大小括號的串,一個合法串的定義如下:

1.空串是合法的;

2.若s爲合法的,則 [s] (s) 也爲合法的;

3.若 a,b爲合法的 , ab 也是合法的。

給你一個長度小於100的串,請加入最少的括號使其合法化。


解法:

區間dp,記錄轉移路徑,類似 poj 2955,不過將dp[i][j]的意義改爲使子段變爲合法的最少插入數,O(n3)。


要點:

1. 初始化的時候,這題與poj 2955 的狀態意義不一樣,所以初始化時有效區間爲inf(因爲要求最小的),無效爲0(方便轉移時邊界的處理);

2.邊界處理,dp[i][i] 爲邊界 (區間長度最短),顯然是1,因爲一個半括號當且僅當加入一個爲最優解;

3.對於區間長度爲2時並且兩個括號失配時的處理,直接是取中間空隙爲中斷點,因爲這種情況需要插入兩個括號,因此不需要特殊處理;

4.根據轉移路徑遞歸重構答案即可。


代碼:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
using namespace std;

const int maxn = 105;
const int inf = 1<<29;
int dp[maxn][maxn];
int path[maxn][maxn];
string s;

bool match(char a, char b) {
    return (a=='('&&b==')') || (a=='['&&b==']');
}

void print(int l , int r){
    if(l > r) return;
    if(l == r){
        if(s[l] == '[' || s[l] == ']') cout <<"[]";
        else cout << "()";
        return;
    }
    if(path[l][r] == -1) {
        cout << s[l];
        print(l+1, r-1);
        cout << s[r];
        return;
    }
    int k = path[l][r];
    print(l, k);
    print(k+1, r);
}

int main() {
    while(getline(cin,s)) {
        for(int i = 0 ; s[i] ; i++) {
            for(int j = 0 ; s[j] ; j++) {
                dp[i][j] = i < j ? inf:0;
            }
        }
        memset(path,-1,sizeof(path));

        for(int i = 0 ; s[i] ; i++)
            dp[i][i] = 1;
        for(int i = 0 ; s[i] ; i++) {
            for(int j = i-1 ; j >= 0 ; j--) {
                if(match(s[j],s[i])){
                    dp[j][i] = dp[j+1][i-1];
                }
                for(int k = j ; k < i ; k++){
                    if(dp[j][i] > dp[j][k]+dp[k+1][i]){
                        dp[j][i] = dp[j][k]+dp[k+1][i];
                        path[j][i] = k;
                    }
                }
            }
        }
        print(0, s.length()-1);
        cout << endl;
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章