题目链接
牛牛的回文串
#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]);
}