0
点赞
收藏
分享

微信扫一扫

与最短路结合的区间dp-牛牛的回文串

德州spark 2022-04-14 阅读 68
c++算法

题目传送门:
https://ac.nowcoder.com/acm/problem/21337
题目大意:
通过以下三种操作,将字符串S变成回文串。如果不能实现,输出-1,否者输出最小的花费

1:在任意位置增加一个字符
2:删除一个字符
3:改变一个字符

输入:
一个字符串S、和整数M
用M条语句来描述能进行的操作
add c x 表示增加c字符需要x的代价
erase c x表示删除c字符需要x的代价
change c1 c2 x表示将c1 改成c2需要x的代价

思路:对于回文串来说,我们要各个元素匹配,将当前元素删除在串的另外一端添加当前元素是等价的。而对于匹配而言,如果某个元素已经匹配了,则相当于将他删除,不再在子问题中考虑。

状态转移的时候,我们有三种情况讨论:
1、将左端点元素str[l] 匹配掉
2、将右端点元素str[r] 匹配掉
3、同时将str[l]和str[r] 匹配掉
所以很快我们可以得出状态转移:

    for(int len=1;len<=lenth;len++){
        for(int l=0;l+len-1<lenth;l++){
            int r=l+len-1;
            f[l][r]=INF;
            if(str[l]==str[r]) f[l][r]=min(f[l][r],f[l+1][r-1]);
            f[l][r]=min(f[l][r],f[l+1][r]+cost[str[l]-'a']);
            f[l][r]=min(f[l][r],f[l][r-1]+cost[str[r]-'a']);
            for(int k=0;k<26;k++){
                LL c1=g[str[l]-'a'][k], c2=g[str[r]-'a'][k];
                f[l][r]=min(f[l][r],f[l+1][r-1]+c1+c2);
            }
        }
    }

这个写法是区间dp的一种较为可读的写法。另外补充cost i 是小写字母i匹配掉的最小花费,g(i,j) 是将小写字母i变成小写字母j的最小花费。通过这种状态转移,我们不遗漏的考虑了所有匹配的情况,接下来我们要实现求costig(i,j) 的函数

void floyd(){
    for(int i=0;i<26;i++) g[i][i]=0;
    
    for(int k=0;k<26;k++)
        for(int i=0;i<26;i++)
            for(int j=0;j<26;j++)
                g[i][j]=min(g[i][j],g[i][k]+g[k][j]);

    for(int i=0;i<26;i++){
        cost[i]=min(cost[i],min(costa[i],coste[i]));
        for(int j=0;j<26;j++){
            cost[i]=min(cost[i],g[i][j]+min(costa[j],coste[j]));
            cost[i]=min(cost[i],costa[j]+g[j][i]);
            for(int k=0;k<26;k++){
                cost[i]=min(cost[i],g[i][j]+costa[k]+g[k][j]);
            }
        }
    }
}

所有的小写字母会映射到一个整数值,我们用 str-'a’来映射。当然这不是重点。我们利用弗洛伊德算法求出了字符i转化到字符j的最小代价,另外我们还维护了一个很重要的东西cost 数组:
我来介绍下他的作用,cost i 表示将字符i 匹配掉的最小花费,有四种情况:
1、将i删除,或者在另一端添加i
2、将i变成j,将j删除或者在另一端添加j
3、i不变,另一端添加j,将j变成i
4、将i变成k,另一端添加j,将j变成k
四种情况不重不漏将cost i的最小值讨论出来

下面贴下总的代码:(感觉比acwing的动态规划题更难QWQ,不过y总真算把我教会了)

注意操作可能比较多,花费比较大,最好开LL来存,避免不必要的错误

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;
typedef long long LL;
const int N=55,INF=1e14;
LL g[N][N];
LL cost[N],costa[N],coste[N];
LL f[N][N];

void init(){
    for(int i=0;i<=26;i++){
        costa[i]=coste[i]=cost[i]=INF;
        for(int j=0;j<=26;j++){
            if(i==j) g[i][j]=0;
            g[i][j]=INF;
        }
    }
}


void floyd(){
    for(int i=0;i<26;i++) g[i][i]=0;
    
    for(int k=0;k<26;k++)
        for(int i=0;i<26;i++)
            for(int j=0;j<26;j++)
                g[i][j]=min(g[i][j],g[i][k]+g[k][j]);

    for(int i=0;i<26;i++){
        cost[i]=min(cost[i],min(costa[i],coste[i]));
        for(int j=0;j<26;j++){
            cost[i]=min(cost[i],g[i][j]+min(costa[j],coste[j]));
            cost[i]=min(cost[i],costa[j]+g[j][i]);
            for(int k=0;k<26;k++){
                cost[i]=min(cost[i],g[i][j]+costa[k]+g[k][j]);
            }
        }
    }
}



int main(){
    string str;
    cin>>str;
    int lenth=str.size();
    int m;
    cin>>m;
    init();
    for(int i=0;i<m;i++){
        string t1;
        cin>>t1;
        if(t1[0]=='c'){
            char d,e;
            LL c;
            cin>>d>>e>>c;
            g[d-'a'][e-'a']=min(g[d-'a'][e-'a'],c);
        }
        else if(t1[0]=='a'){
            char d;
            LL c;
            cin>>d>>c;
            costa[d-'a']=min(costa[d-'a'],c);
        }
        else{
            char d;
            LL c;
            cin>>d>>c;
            coste[d-'a']=min(coste[d-'a'],c);
        }
    }
    floyd();
    memset(f,0,sizeof f);
    for(int len=1;len<=lenth;len++){
        for(int l=0;l+len-1<lenth;l++){
            int r=l+len-1;
            f[l][r]=INF;
            if(str[l]==str[r]) f[l][r]=min(f[l][r],f[l+1][r-1]);
            f[l][r]=min(f[l][r],f[l+1][r]+cost[str[l]-'a']);
            f[l][r]=min(f[l][r],f[l][r-1]+cost[str[r]-'a']);
            for(int k=0;k<26;k++){
                LL c1=g[str[l]-'a'][k], c2=g[str[r]-'a'][k];
                f[l][r]=min(f[l][r],f[l+1][r-1]+c1+c2);
            }
        }
    }
    
    if(f[0][lenth-1]==INF) puts("-1");
    else cout<<f[0][lenth-1]<<endl;
    return 0;
}
```2022413日,暴雨————————————于南昌
举报

相关推荐

0 条评论