poj 2955 Brackets 【區間DP】

題意:

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

1.空串是合法的;

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

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

給你一個長度小於100的串,求其所包含的的最長的合法串所包涵的字符數。


解法:

經典區間dp,括號匹配問題,o(n3)

狀態:

dp[i][j] 表示 s[i]到s[j]字符區間內的最長長度。

轉移方程:

if(s[i] 與 s[j] 匹配 ) --> dp[i][j] = max(dp[i+1][j-1]+2 , dp[i][k]+dp[k+1][j]);

else --> max(dp[i+1][j-1] , dp[i][k]+dp[k+1][j]);

初始化:

dp的邊界便是區間長度爲1的情況,並且這種情況下的答案是0,所以全部初始化爲0即可。同時注意到轉移是由區間長度由小到大來的,所以j的循環要改爲由i-1遞減得到。


WA點:

最開始寫的時候k的循環由 j+1 開始的,這樣的話就會丟失一種狀態 : dp[j][j]+dp[j+1][i] ,導致wa。


代碼:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <string>
#include <stack>
#include <queue>
#include <algorithm>
#include <cmath>
using namespace std;

const int maxn = 1e2+5;
int dp[maxn][maxn];

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

int main(){
    string s;
    while(getline(cin,s), s!="end"){
        memset(dp, 0, sizeof(dp));
        for(int i = 0; s[i] ; i++) {
            for(int j = i-1; j >= 0 ; j--) {
                dp[j][i] = match(s[j], s[i]) ? dp[j+1][i-1] + 2 : dp[j+1][i-1];
                for(int k = j ; k < i ; k++)
                    dp[j][i] = max(dp[j][i], dp[j][k]+dp[k+1][i]);
            }
        }
        cout << dp[0][s.length()-1] << endl;
    }
	return 0;
}

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