原题:https://ac.nowcoder.com/acm/problem/21337
题意:给一个S字符串,通过三种操作(添加,删除,修改)变成回文串的的最小代价。考虑区间
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]表示i~j是回文串的最下代价
- S [ i ] = S [ j ] S[i]=S[j] S[i]=S[j] , d p [ i ] [ j ] = d p [ i + 1 ] [ j − 1 ] dp[i][j]=dp[i+1][j-1] dp[i][j]=dp[i+1][j−1]
- 考虑去掉端点i的影响可以删去i或在另一端加上i,记 c o s t [ i ] cost[i] cost[i]为去掉i的影响的代价则 d p [ i ] [ j ] = m i n { d p [ i + 1 ] [ j ] + c o s t [ S [ i ] ] , d p [ i ] [ j − 1 ] + c o s t [ S [ j ] ] } dp[i][j]=min\{ dp[i+1][j]+cost[S[i]],dp[i][j-1]+cost[S[j]]\} dp[i][j]=min{dp[i+1][j]+cost[S[i]],dp[i][j−1]+cost[S[j]]}
- 将i,j变成相同的字母k d p [ i ] [ j ] = m i n { d p [ i + 1 ] [ j − 1 ] + d i s [ S [ i ] ] [ k ] + d i s [ S [ j ] ] [ k ] } dp[i][j]=min\{dp[i+1][j-1]+dis[S[i]][k]+dis[S[j] ][k]\} dp[i][j]=min{dp[i+1][j−1]+dis[S[i]][k]+dis[S[j]][k]}
考虑计算
c
o
s
t
[
i
]
,
d
i
s
[
i
]
[
j
]
cost[i],dis[i][j]
cost[i],dis[i][j] 由于有多次变换,可以通过floyd 求出i->j的最短路
考虑cost[i],
- 由于添加和删除是可以等效的 c o s t [ i ] = m i n { c o s t _ a d d [ i ] , c o s t _ d e l [ i ] } cost[i]=min\{cost\_add[i],cost\_del[i]\} cost[i]=min{cost_add[i],cost_del[i]}
- 将i->j再删除或添加 c o s t [ i ] = m i n { d i s [ i ] [ j ] + m i n { c o s t _ a d d [ j ] , c o s _ d e l [ j ] } } cost[i]=min\{dis[i][j]+min\{cost\_add[j],cos\_del[j]\}\} cost[i]=min{dis[i][j]+min{cost_add[j],cos_del[j]}}
- 添加j ,j将i,j变成k c o s t [ i ] = m i n { c o s t _ a d d [ j ] + d i s [ j ] [ k ] + d i s [ i ] [ k ] } cost[i]=min\{cost\_add[j]+dis[j][k]+dis[i][k]\} cost[i]=min{cost_add[j]+dis[j][k]+dis[i][k]}
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=50;
string str;
ll dp[N][N],mp[N][N],dis[N][N],cost_add[N],cost_del[N],inf=1e16,cost[N];
int m;
void init(){
for(int k=0;k<26;k++){
for(int i=0;i<26;i++) {
for(int j=0;j<26;j++){
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
}
}
}
for(int i=0;i<26;i++){
cost[i]=min(cost_add[i],cost_del[i]);//1.添加/删除
for(int j=0;j<26;j++){
cost[i]=min(cost[i],dis[i][j]+min(cost_add[j],cost_del[j]));//i->j 添加或删除
for(int k=0;k<26;k++){
cost[i]=min(dis[i][k]+cost_add[j]+dis[j][k],cost[i]);
}
}
}
}
int main(){
cin>>str;
int n=str.size();
str=" "+str;
for(int i=0;i<26;i++){
cost_add[i]=cost_del[i]=cost[i]=inf;
for(int j=0;j<26;j++){
dis[i][j]=inf;
}
}
for(int i=0;i<26;i++) dis[i][i]=0;
cin>>m;
string tmp;
while(m--){
cin>>tmp;
if(tmp[0]=='a'){
char t;ll x;
cin>>t>>x;
cost_add[t-'a']=min(cost_add[t-'a'],x);
}
if(tmp[0]=='e'){
char t;ll x;
cin>>t>>x;
cost_del[t-'a']=min(cost_del[t-'a'],x);
}
if(tmp[0]=='c'){
char u,v;ll x;
cin>>u>>v>>x;
dis[u-'a'][v-'a']=min(x,dis[u-'a'][v-'a']);
}
}
init();
for(int i=n;i>=1;i--){
for(int j=i+1;j<=n;j++){
dp[i][j]=inf;
if(str[i]==str[j]){
dp[i][j]=dp[i+1][j-1];
}
dp[i][j]=min(dp[i][j],dp[i+1][j]+cost[str[i]-'a']);
dp[i][j]=min(dp[i][j],dp[i][j-1]+cost[str[j]-'a']);
for(int k=0;k<26;k++){
dp[i][j]=min(dp[i][j],dp[i+1][j-1]+dis[str[i]-'a'][k]+dis[str[j]-'a'][k]);
}
}
}
if(dp[1][n]==inf) cout<<"-1\n";
else cout<<dp[1][n]<<endl;
return 0;
}