// 并列,嵌套两种方法 // 思路s[l...r]范围内至少插入多少字符能让它变正确 // 两头端点的讨论和划分点的讨论揉在一起的题 #include<bits/stdc++.h> #define int long long using namespace std; const int N=1e5+10; const int MOD=1e9+7; const int INF=0x3f3f3f3f3f3f3f3f; int dx[4] = {1, -1, 0, 0}; int dy[4] = {0, 0, 1, -1}; int f2(string& s,int l,int r,vector<vector<int>>& f){ // base case: // l==r,不管剩哪一个字符都缺一个 if(l==r){ return 1; } // +这个base case 之后下面的边界就会少扣一些 if(l+1==r){ if((s[l]=='('&&s[r]==')')||(s[l]=='['&&s[r]==']')){ return 0; } return 2; } // 正常情况: // [l...r]范围字符数量大于等于3 if(f[l][r]!=-1){ return f[l][r]; } // 两种可能性展开 int p1=INT_MAX; // l位置和r位置可以自我消化(本来就是配对的) if((s[l]=='('&&s[r]==')')||(s[l]=='['&&s[r]==']')){ p1=f2(s,l+1,r-1,f);//那就看看中间范围上要插入几个 } int p2=INT_MAX; // 基于每个划分点做可能性划分 for(int k=l;k<r;k++){ // l...k k+1...r // 来一个k就计算左侧需要几个,右侧需要几个加起来 // 枚举所有可能的k,那其中划分这种可能的最小值抓出来 p2=min(p2,f2(s,l,k,f)+f2(s,k+1,r,f)); } int ans=min(p1,p2); f[l][r]=ans; return ans; } void sol(){ string s;cin>>s; int n=s.size(); vector<vector<int>> f(n,vector<int>(n,-1)); cout<<f2(s,0,s.size()-1,f); } signed main(){ int T;T=1; // cin>>T; while(T--){ sol(); } return 0; }