牛牛的回文串
#include <bits/stdc++.h>
using namespace std;
#define ll long long
/*
解决一个回文串可以发现,添加一个字符和删除一个字符是等价的,删除一个字符相当于在另一侧添加一个字符,所以只需要计算删除一个字符
所需要的的代价即可,删除一个字符可以用过
1. 先将该字符change成另一个字符再删除
2. 添加任意一个字符再修改成该字符相当于添加
3. 将该字符替换成另一个字符c在通过添加另一个字符
4. 将该字符替换成另一个字符c,再任意添加一个字符c1,再将c1替换成c
可以先用floyd来求出任意两个字符转换的最小代价,再去考虑上述四种情况求出cost
然后使用dp来解决问题
dp状态转移方程如下
dp[i][j]表示i~j是回文串的最小代价
从后往前和从前往后其实都一样
然后考虑dp[i+1~n]dp[j-1~n]都是已经处理好的了,
所以
if(s[i]==s[j])dp[i][j]=dp[i+1][j-1];
考虑不相等的情况
1. 可以将s[i]删除val = dp[i+1][j] + cost[s[i]-'a']
2. 可以将s[j]删除val = dp[i][j-1] + cost[s[j]-'a']
3. 可以将s[i],s[j] 替换成某个字符 k
4. 可以将s[i]替换成s[j],或者s[j]替换成s[i]
*/
const int N = 60;
ll dp[N][N];
ll cost[30], change[30][30];
ll cost_erase[30], cost_add[30];
const ll INF = 1e15 + 10;
char s[N];
void floyd() {
for (int k = 0; k < 26; k++) {
for (int i = 0; i < 26; i++) {
for (int j = 0; j < 26; j++) {
change[i][j] = min(change[i][j], change[i][k] + change[k][j]);
}
}
}
for (int i = 0; i < 26; i++) {
for (int j = 0; j < 26; j++) {
cost[i] = min(cost[i], min(cost_add[i], cost_erase[i]));
cost[i] = min(cost[i], change[i][j] + min(cost_add[j], cost_erase[j]));
cost[i] = min(cost[i], cost_add[j] + change[j][i]);
for (int k = 0; k < 26; k++) {
cost[i] = min(change[i][j] + cost_add[k] + change[k][j], cost[i]);
}
}
}
}
int main() {
scanf("%s", s + 1);
int m;
scanf("%d", &m);
for (int i = 0; i < 26; i++) {
cost_erase[i] = cost_add[i] = cost[i] = INF;
for (int j = 0; j < 26; j++) {
change[i][j] = INF;
}
}
while (m--) {
char op[20], ch[2], ch1[2];
int val;
scanf("%s", op);
if (op[0] == 'e') {
scanf("%s%d", ch, &val);
cost_erase[ch[0] - 'a'] = min(cost_erase[ch[0] - 'a'], 1ll * val);
}
if (op[0] == 'a') {
scanf("%s%d", ch, &val);
cost_add[ch[0] - 'a'] = min(cost_add[ch[0] - 'a'], 1ll * val);
}
if (op[0] == 'c') {
scanf("%s%s%d", ch, ch1, &val);
change[ch[0] - 'a'][ch1[0] - 'a'] =
min(change[ch[0] - 'a'][ch1[0] - 'a'], 1ll * val);
}
}
floyd();
int len = strlen(s + 1);
for (int i = len; i >= 1; i--) {
for (int j = i + 1; j <= len; j++) {
dp[i][j] = INF;
if (s[i] == s[j])
dp[i][j] = dp[i + 1][j - 1];
dp[i][j] = min(dp[i][j], dp[i][j - 1] + cost[s[j] - 'a']);
dp[i][j] = min(dp[i][j], dp[i + 1][j] + cost[s[i] - 'a']);
dp[i][j] = min(dp[i][j], dp[i + 1][j - 1] + min(change[s[i] - 'a'][s[j] - 'a'], change[s[j] - 'a'][s[i] - 'a']));
for (int k = 0; k < 26; k++) {
dp[i][j] = min(dp[i][j], dp[i + 1][j - 1] + change[s[i] - 'a'][k] + change[s[j] - 'a'][k]);
}
}
}
if (dp[1][len] == INF)
printf("-1\n");
else
printf("%lld\n", dp[1][len]);
}
题解:我太菜了,解不动,去看dl的解释吧……题解链接