DP - 區間DP - Brackets - POJ - 2955
題意:
用以下方式定義合法的括號字符串1.空串是合法的2.如果S是合法的,那麼(S)和[S]也都是合法的3.如果A和B是合法的,那麼AB是一個合法的字符串.
現給定一個僅含"()"和"[]"的括號序列s,要求序列s中的合法括號字符子序列的最大長度。
Sample Input:
((()))
()()()
([]])
)[)(
([][][)
end
Sample Output:
6
6
4
0
6
數據範圍:
序列長度∣s∣<=100Time limit:1000 ms,Memory limit:65536 kB
分析:
本題是求合法子序列的最大長度,因此不能用棧來做括號匹配。
事實上,合法括號的計算是相互獨立的。
可用區間DP來計算。
狀態表示:f[i][j]:區間[i,j]中的合法括號數量的最大值。
狀態計算:對區間[l,r]內的合法括號數量可分爲[l,k]和[k+1,r]兩部分,k爲分界點,k∈[l,r−1]。
即f[l][r]=max(f[l][k]+f[k+1][r])。
特別地,當k=r時,即求整個區間的最大值,有兩種情況:
①、s[l]=s[r],則f[l][r]=f[l+1][r−1]。②、s[l]=s[r],則f[l][r]=f[l+1][r−1]+2。
最後對每個長度爲len的區間[l,r],枚舉分界點k求最大值更新到f[l][r]即可。
代碼:
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=110;
char s[N];
int f[N][N];
bool check(int l,int r)
{
if( (s[l]=='('&&s[r]==')')||(s[l]=='['&&s[r]==']') )return true;
return false;
}
int main()
{
while(~scanf("%s",s+1),strcmp("end",s+1))
{
memset(f,0,sizeof f);
int n=strlen(s+1);
for(int len=2;len<=n;len++)
for(int l=1;l+len-1<=n;l++)
{
int r=l+len-1;
f[l][r]=f[l+1][r-1];
if(check(l,r)) f[l][r]+=2;
for(int k=l;k<r;k++) f[l][r]=max(f[l][r],f[l][k]+f[k+1][r]);
}
cout<<f[1][n]<<endl;
}
return 0;
}