用dp(i, j)表示区间[i, j]变成回文字符串需要的最小代价
如果s[i] == s[j]
则dp(i, j) = dp(i + 1, j - 1)
否则我们就有四种决策消除i, j这两个位置的冲突
1.在左边添加一个s[j]字符
2.删除s[j]
3.在右边添加一个s[i]字符
4.删除s[i]
我们用add(i)表示添加第i个字符的代价, dele(i)表示删除第i个字符的代价
则dp(i, j) = min(dp(i + 1, j) + add(i), dp(i + 1, j) + dele(i), dp(i, j - 1) + dele(j), dp(i, j - 1) + add(j))
代码如下:
#include <queue>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define MAX_N 3000
#define INF 0x3f3f3f
using namespace std;
typedef long long int ll;
int dp[MAX_N][MAX_N];
int main()
{
//freopen("1.txt", "r", stdin);
int N, M;
char ID[MAX_N];
int add[30], dele[30];
while (cin >> N >> M)
{
scanf("%s", ID);
for (int i = 0; i < N; i++)
{
getchar();
char t = getchar();
scanf("%d%d", &add[t - 'a'], &dele[t - 'a']);
}
memset(dp, 0, sizeof(dp));
for (int l = 2; l <= M; l++)
for (int i = 0; i < M; i++)
{
int j = i + l - 1;
if (i >= 0 && i < M && j >= 0 && j < M)
{
if (ID[i] == ID[j])
dp[i][j] = dp[i + 1][j - 1];
else
{
int mincost = INF;
///刚开始思路有点问题,认为只有ID[i] == ID[j - 1]的时候才能尝试删除j位置的字符
///实际上不论什么情况,都可以尝试删除j位置的字符
//if (ID[i] == ID[j - 1])
mincost = min(mincost, dp[i][j - 1] + dele[ID[j] - 'a']);
//if (ID[i + 1] == ID[j])
///和上述同样的错误
mincost = min(mincost, dp[i + 1][j] + dele[ID[i] - 'a']);
int temp = min(dp[i][j - 1] + add[ID[j] - 'a'], dp[i + 1][j] + add[ID[i] - 'a']);
dp[i][j] = min(mincost, temp);
}
}
}
printf("%d\n", dp[0][M - 1]);
}
return 0;
}
因篇幅问题不能全部显示,请点此查看更多更全内容