题目链接
牛牛喜欢回文串,牛妹给了牛牛一个字符串S,牛牛想把S变成回文串
牛牛可以做如下三种操作
1:在任意位置增加一个字符
2:删除一个字符
3:改变一个字符
每种操作都有限定的字符,比如,只能删除’a’,增加’b’,把’c’变成’d’等等
每种操作都有相应的代价
用M条语句来描述能进行的操作
add c x 表示增加c字符需要x的代价
erase c x表示删除c字符需要x的代价
change c1 c2 x表示将c1 改成c2需要x的代价
求牛牛想要得到回文串需要的最少代价
如果不行输出-1
串的长度<=50
用dp(i,j)表示把[i, j]这一区间变成回文串的最小代价,那么dp(i, j)可以由dp(i+1, j), dp(i, j-1), dp(i+1, j-1)这三种状态转移而来。
但是因为它给出的操作可以出现很多变换,直接进行它所给的操作有可能不会得到最优解:比如change(a,c) = 10,add( a ) = 1,add( c ) = 100,那么直接add( c )的代价要比先add( a )再change(a,c)要大,而change之间也类似。所以我们用类似最短路的算法预处理出所有类型操作的最小费用(代价为inf = 不能进行该操作)。
预处理完之后,对于区间(i, j),它可能的转移:
AC代码:
#include
#define ll long long
using namespace std;
const int maxn = 55;
const ll inf = 0x3f3f3f3f;
ll dp[maxn][maxn];
char s[maxn];
int a[maxn];
ll add[maxn],era[maxn],to[maxn][maxn];
void up_add(){//spfa思想更新add操作
int inq[30];
queue q;
for(int i = 0; i < 26; ++i){
q.push(i);inq[i] = 1;
}
while(q.size()){
int u = q.front();q.pop();inq[u] = 0;
for(int i = 0;i < 26;++i){
if(add[i] > add[u] + to[u][i]){
add[i] = add[u] + to[u][i];
if(!inq[i]) q.push(i), inq[i] = 1;
}
}
}
}
void up_era(){//spfa思想更新era操作
int inq[30];
queue q;
for(int i = 0; i < 26; ++i){
q.push(i);inq[i] = 1;
}
while(q.size()){
int u = q.front();q.pop();inq[u] = 0;
for(int i = 0;i < 26;++i){
if(era[i] > to[i][u] + era[u]){
era[i] = to[i][u] + era[u];
if(!inq[i]) q.push(i), inq[i] = 1;
}
}
}
}
ll cul(int l,int r){
if(l > r) return 0;
return dp[l][r];
}
int main(){
// memset(dp,0x3f,sizeof dp);
// memset(add,0x3f,sizeof add);
// memset(era,0x3f,sizeof era);
// memset(to,0x3f,sizeof to);
for(int i = 0; i < maxn; ++i){//因为后面可能会出现3个inf相加,
//所以inf定小一点防止爆ll
add[i] = era[i] = inf;
for(int j = 0; j < maxn; ++j){
dp[i][j] = to[i][j] = inf;
}
}
scanf("%s",s+1);
int len = strlen(s+1);
for(int i = 1; i <= len; ++i) a[i] = s[i] - 'a';
for(int i = 1; i <= len; ++i) dp[i][i] = 0;
int n; scanf("%d",&n);
while(n--){
char op[10],c[2];
int x;
scanf("%s",op);
if(op[0] == 'a'){
scanf("%s%d",c,&x);
add[c[0]-'a'] = x;
}
else if(op[0] == 'e'){
scanf("%s%d",c,&x);
era[c[0]-'a'] = x;
}
else{
char c2[2];
scanf("%s%s%d",c,c2,&x);
to[c[0]-'a'][c2[0]-'a'] = x;
}
}
for(int k = 0; k < 26; ++k) {//Floyd思想更新to操作
for(int i = 0; i < 26; ++i){
for(int j = 0; j < 26; ++j){
if(i == j) to[i][j] = 0;
to[i][j] = min(to[i][j],to[i][k] + to[k][j]);
}
}
}
up_add(); up_era();
for(int d = 1; d < len; ++d){
for(int r = d+1; r <= len; ++r){
int l = r - d;
//erase
dp[l][r] = min(cul(l+1, r) + era[a[l]], dp[l][r]);
dp[l][r] = min(cul(l, r-1) + era[a[r]], dp[l][r]);
dp[l][r] = min(cul(l+1, r-1) + era[a[l]] + era[a[r]], dp[l][r]);
//add && change
for(int v = 0; v < 26; ++v){
dp[l][r] = min(dp[l][r], cul(l, r-1) + add[v] + to[a[r]][v]);
dp[l][r] = min(dp[l][r], cul(l+1, r) + add[v] + to[a[l]][v]);
dp[l][r] = min(dp[l][r], cul(l+1, r-1) + to[a[r]][v] + to[a[l]][v]);
}
//cout<<"l:"<