牛牛的回文串 区间dp 最短路

该博客主要探讨如何利用动态规划和Floyd算法解决字符串到回文串的最小编辑代价问题。文章介绍了算法的实现细节,包括状态转移方程和代价计算,并给出了完整的C++代码实现。通过对添加、删除、修改操作的成本计算,实现了从给定字符串到回文串的最优转换路径。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原题: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][j1]
  • 考虑去掉端点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][j1]+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][j1]+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;
} 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值