题目
思路
考虑区间DP。
设dp[i][j]为从i到j这段区间被修正为回文串的最小花费
c[cc][1]为添加字符cc的花费
c[cc][2]为删去字符cc的花费
s为题目给出的字符串。
- 用[i + 1,j]区间转移:这种转移相当于在[i+1,j]区间的左边加入一个字符,让[i,j]变为回文的方法为在左边删去该字符或在右边加上该字符,有转移方程:
dp[i][j] = min(dp[i][j],dp[i + 1][j] + min(c[int(s[i])][1],c[int(s[i])][2]));
- 用[i,j − 1][i,j − 1]区间转移:这种转移相当于在[i,j−1][区间的右边加入一个字符,方法同上:
dp[i][j] = min(dp[i][j],dp[i][j - 1] + min(c[int(s[j])][1],c[int(s[j])][2]));
- 当前区间[i,j]满足s[i] == s[j],直接用[i + 1,j − 1]转移:
if(j - i == 1) dp[i][j] = 0;
else dp[i][j] = min(dp[i][j],dp[i + 1][j - 1]);
代码
#include<bits/stdc++.h>
using namespace std;
int n,m,dp[2101][2101],c[255][3],x,y;
//从i到j这段区间被修正为回文串的最小花费
char s[2101],cc;
int main()
{
cin>>n>>m;
cin>>s + 1;
for(int i = 1;i <= n;i++)
{
cin>>cc>>x>>y;
c[int(cc)][1] = x;
c[int(cc)][2] = y;
}
memset(dp,0x3f,sizeof(dp));
for(int i = 1;i <= m;i++) dp[i][i] = 0;
for(int l = 1;l <= m;l++)
for(int i = 1;l + i - 1 <= m;i++)
{
int j = i + l - 1;
dp[i][j] = min(dp[i][j],dp[i + 1][j] + min(c[int(s[i])][1],c[int(s[i])][2]));
dp[i][j] = min(dp[i][j],dp[i][j - 1] + min(c[int(s[j])][1],c[int(s[j])][2]));
if(s[i] == s[j])
{
if(j - i == 1) dp[i][j] = 0;
else dp[i][j] = min(dp[i][j],dp[i + 1][j - 1]);
}
}
cout<<dp[1][m];
return 0;
}
怎么样?听懂了吗?如果听懂了就请点赞收藏加关注支持一下吧!