CF162J Brackets
看到两位用栈匹配括号的大佬,这里提供另一个思路。
对于括号的问题,我们考虑区间DP。
设状态 \(dp[i][j]\) 表示使区间 \([i,j]\) 内的括号匹配需要添加的括号数量,则转移方程如下:
\(1\) :区间两边括号匹配时,因为最外层不需要匹配,需要添加的括号数量取决于最外层括号内的需要添加的括号数量,也就是 \(dp[i+1][j-1]\) 的值。
\[dp[i][j]=\min\{dp[i][j],dp[i+1][j-1]\}
\]
\(2\) :枚举分割点 \(k\) ,把原区间分 \([i,k]\) 和 \([k+1,j]\) 两个区间,然后求和,把使两个子区间需要添加的括号数量合起来,就是总区间需要添加的括号数量。
\[dp[i][j]=\min\{dp[i][j],dp[i][k]+dp[k+1][j])\}
\]
最后,如果使整个区间的括号匹配不需要任何括号,也就是说 \(dp[0][n-1]=0\) ,那么说明这个序列本来就是匹配的,输出 YES
,否则输出 NO
。
虽然复杂度是 \(O(n^3)\) ,但是由于序列长度最长只有 \(100\) ,还是可以做的。
C++版本代码如下:
#include <bits/stdc++.h>
using namespace std;
int f[600][600];
char s[600];
int main()
{scanf("%s",s);int n=strlen(s);for(int i=0;i<n;i++)f[i][i]=1;for(int l=2;l<=n;l++)for(int i=0;i+l-1<n;i++){int j=i+l-1;f[i][j]=l;if((s[i]=='('&&s[j]==')')||(s[i]=='['&&s[j]==']'))f[i][j]=min(f[i][j],f[i+1][j-1]);for(int k=i;k<j;k++)f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]); }if(!f[0][n-1])printf("YES"); else printf("NO");return 0;
}