今天的算法设计的作业code 中的区间DP大部分都是设计和字符串有关系的区间DP 属于经典模型
下面简单整理一下:
回文子串
输入一个字符串 Str ,输出 Str 里最长回文子串的长度。 回文串:指 aba 、 abba 、 cccbccc 、 aaaa 这种左右对称的字符串。 串的子串:一个串的子串指此(字符)串中**连续**的一部分字符构成的子(字符)串 例如 abc 这个串的子串:空串、 a 、 b 、 c 、 ab 、 bc 、 abc
输出最长回文子串的长度 L 。
["daabaac"]
["5"]
这里分享用区间DP解回文问题的解法:
这里我们的dp数组用的是bool类型~存的是当前i,j是否为回文序列
dp[i][j] <---- dp[i+1][j-1] &&(a[i]==a[j]) 注意边界1 和2 的时候就可以了
代码如下:
#include<iostream>
using namespace std;
const int N=1e5+10;
string str;
int dp[2010][2010];
int res=1;
int main()
{
cin>>str;
int n=str.size();
for(int len=1;len<=n;len++)
for(int i=0;i+len-1<n;i++){
int j=i+len-1;
if(i==j)dp[i][j] =1;
else if((str[i]==str[j])&&(len==2||dp[i+1][j-1])){
dp[i][j] =1;
if(len>res)res=len;
}
}
cout<<res;
}
POJ 2955 括号问题
给定只含有中小括号的字符串 问最多匹配的数目
也是区间DP的经典想法,由小区间可以递推出来我们的大区间,f [i][j] 为i-j的最多的匹配的数目
f[i][j] = f[i+1][j-1] +check(i,j)(检查 i j是否匹配)
枚举断点 f[i][j] =f[i][k] +f[k+1][j]; 维护最大值
代码如下:
#include<iostream>
#include<cstring>
using namespace std;
int dp[1010][1010];
string str;
bool check(int i,int j)
{
if(str[i]=='('&&str[j]==')')return 1;
if(str[i]=='['&&str[j]==']')return 1;
return 0;
}
int main()
{
while(cin>>str,str!="end")
{
memset(dp,0,sizeof dp);
int n=str.size();
for(int len=1;len<=n;len++)
for(int i=0;i+len-1<n;i++)
{
int j=i+len-1;
dp[i][j]=dp[i+1][j-1]+check(i,j);
for(int k=i;k<j;k++)
dp[i][j] = max(dp[i][j],dp[k+1][j]+dp[i][k]);
}
cout<<dp[0][n-1]*2<<endl;
}
}
POJ 3280
给定字符串 以及每个其中每个字母删除和插入的代价 求将原来的字符串变成回文串的最小代价
考虑dp[i][j] 为 i-j段变成回文串的最小代价,它是由dp[i+1][j] 和dp[i][j-1] 共同来一起决定的
对于dp[i+1][j] 怎么递推到我们的dp[i][j]呢?容易知道它就是 去掉a[i] 或者在 a[j+1] 加上插入一个a[i]
同里 dp[i][j-1]也是这样操作的~可以发现我们只需要插入和删除的最小的那个值就可以了 我们只需要那个值来进行操作~
注意边界~
代码如下:
#include<iostream>
using namespace std;
string str;
int v[1010];
int dp[2010][2010];
int n,m;
int main()
{
cin>>m>>n;
cin>>str;
for(int i=1;i<=n;i++)
{
char c;
int value1,value2;
cin>>c>>value1>>value2;
v[c-'a'] = min(value1,value2);
}
for(int len=1;len<=n;len++)
for(int i=0;i+len-1<n;i++)
{
int j=i+len-1;
if(str[i]==str[j])dp[i][j] = dp[i+1][j-1];
else
dp[i][j]= min(dp[i+1][j]+v[str[i]-'a'],dp[i][j-1]+v[str[j]-'a']);
}
cout<<dp[0][n-1];
}