poj 2955"Brackets"(区间DP)
https://www.cnblogs.com/violet-acmer/p/9852294.html
题意:
给你一个只由 '(' , ')' , '[' , ']' 组成的字符串s[ ],求最大匹配?
题解:
定义dp[ i ][ j ] : 从第i个字符到第j个字符的最大匹配。
步骤:
(1) : 如果s[ i ] 与 s[ j ]匹配,那么dp[ i ][ j ] = 2+dp[ i+1 ][ j-1 ];反之,dp[ i ][ j ] = 0;
(2) : 接下来,从 i 到 j 将区间划分成两部分[ i , k ]和[ k+1 , j ],( i ≤ k ≤ j-1 ),状态转移方程为
dp[ i ][ j ]=max( dp[ i ][ j ] , dp[ i ][ k ]+dp[ k+1 ][ j ] );
AC代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 #define mem(a,b) memset(a,b,sizeof(a)) 6 const int maxn=100+10; 7 8 char s[maxn]; 9 int dp[maxn][maxn]; 10 11 // (int)'(' = 40,(int)')' = 41; 12 // (int)'[' = 91,(int)']' = 93; 13 bool isMatch(int i,int j){//判断s[i]与s[j]是否匹配 14 return (s[j]-s[i] == 1 || s[j]-s[i] == 2) ? true:false; 15 } 16 int Solve() 17 { 18 int sLen=strlen(s); 19 int res=0; 20 for(int i=0;i < sLen;++i) 21 { 22 dp[i][i]=0; 23 dp[i][i+1]=(isMatch(i,i+1) ? 2:0); 24 res=dp[i][i+1]; 25 } 26 for(int len=3;len <= sLen;++len)//区间长度 27 { 28 for(int i=0;i+len-1 < sLen;++i) 29 { 30 int j=i+len-1; 31 dp[i][j]=(isMatch(i,j) ? 2+dp[i+1][j-1]:0); 32 for(int k=i;k < j;++k) 33 dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]); 34 res=max(res,dp[i][j]); 35 } 36 } 37 return res; 38 } 39 int main() 40 { 41 // freopen("C:\\Users\\lenovo\\Desktop\\in.txt\\poj2955.txt","r",stdin); 42 while(scanf("%s",s) && s[0] != 'e') 43 printf("%d\n",Solve()); 44 45 return 0; 46 }
分析:
能使用区间DP,必须得满足两个条件:
(1) : 问题具有最优子结构
如果区间对于状态转移方程:dp[ i ][ j ]=max( dp[ i ][ j ] , dp[ i ][ k ]+dp[ k+1 ][ j ] );
如果子结构dp[ i , k ],dp[ k+1 , j ]所求的解为最优解,那么dp[ i , j ]必定也是最优解,反之亦成立。
(2) : 无后效性
区间[ i , j ]的子区间 [ i , k ] 和 [ k+1 , j ] 是通过何种方式取得最优解的并不影响 [ i , j ] 是以何种方式取得最优解