区间dp
看了刘汝佳的书,恰巧发现了这么一道题,抱着虐菜的心态,反被虐了一下午,自己还是太渣渣。
题目类型还是区间dp,对于一个一维序列,通过从中划分为两个,四个。。。。个序列,直到剩余一个括号或者没有括号,一个括号则不是规则的,删掉,返回1,空的序列则是规则的,返回0,通过这样不断递归得到最优解。
关于递归方程式,借用刘汝佳的书里的状态划分:
1):如果序列式形如(s‘)或【s'】,则只需将s'变为规则的即可。dp【l】【r】=min(dp【l】【r】,dp【l+1】【r-1】)
2):如果序列形如(s',【s’,s'),s'】,则删掉边上的不规则的,将s'变为规则的即可。dp【l】【r】=min(dp【l】【r】,dp【l+1】【r】+1,dp【l】【r+1】+1)
3):对任意大于1的序列,均可划分为两部分,dp【l】【r】=min(dp【l】【r】,dp【l】【k】+dp【k+1】【r】)
代码里的dp【l】【r】记录的是l到r长度上需要删除的最小括号数。
#include <iostream>
#include <cstring>
#include <string>
using namespace std;
int dp[105][105];
int mark[105][105];
string s;
int min(int a,int b)
{
return a>b?b:a;
}
int interval(int l,int r)
{
if (l>r)
return 0;
if (l==r)
{
dp[l][r]=1;
return 1;
}
if (mark[l][r]!=0)
return dp[l][r];
dp[l][r]=999999;
if ((s[l]=='('&&s[r]==')')||(s[l]=='['&&s[r]==']'))
dp[l][r]=min(dp[l][r],interval(l+1,r-1));
dp[l][r]=min(dp[l][r],interval(l+1,r)+1);
dp[l][r]=min(dp[l][r],interval(l,r-1)+1);
for (int k=l;k<r;k++)
dp[l][r]=min(dp[l][r],interval(l,k)+interval(k+1,r));
mark[l][r]=1;
return dp[l][r];
}
int main()
{
while (cin>>s)
{
if (s=="end")
break;
memset(mark,0,sizeof(mark));
memset(dp,0,sizeof(dp));
interval(0,s.length()-1);
cout<<s.length()-dp[0][s.length()-1]<<endl;
}
return 0;
}