• 【算法学习笔记】70.回文序列 动态规划 SJTU OJ 1066 小M家的牛们


    这个题很多地方暗示了DP的路径。

    我们处理时,dp[i][j]可以认为是从i坐标到j坐标的序列达到回文效果需要的最小代价,以此向外扩展,最终得到dp[0][M-1]就是结果。

    我们要注意到处理dp[i][j]时,我们需要知道 dp(i+1,j-1)的结果,所以i必须降序,j必须升序,才能保证在计算dp(i,j)时,可以利用已经计算过的结果。

    所以 

    i应该从M-2 到 0 递减

    j在内层 从i+1到M-1 递增

    在处理dp(i,j)时,第一要看name[i]和name[j]是否相等,如果相等的话,那么直接向内扣一层就可以了

    dp[i][j] = dp[i+1][j-1]

    否则我们要进行改造,使其成为回文字符串

    这个改造有四种方法

    1.先让i+1到j是回文的 再在最后加一个name[i]

    2.先让i+1到j是回文的 再把前面的name[i]删掉 

    3.先让i到j-1是回文的 再在最前面加一个name[j] 

    4.先让i到j-1是回文的 再在最后的name[j]删掉 

    选择一种消耗最小的方案就可以了。

    代码如下

    #include <iostream>
    #include <cstring>
    
    using namespace std;
    
    struct chr
    {
        char c;
        int add;
        int del;
    };
    
    chr v[30];
    int N,M;
    string name;
    
    void init(){
        cin>>N>>M;
        //N是不同字母的数量
        //M是原始名字的长度
        cin>>name;
        //记录字母cost情况
        for (int i = 0; i < N; ++i)
        {
            char c;
            cin>>c;
            v[c-'a'].c = c;
            cin >>v[c-'a'].add >> v[c-'a'].del;
        }
    }
    
    unsigned long long dp[2500][2500]={0};//存储的是 从第i个字母 到 第j个字母 的回文最小消耗
    
    
    int build(){
        //从后向前填满dp[i][j]
        for (int i = M-2; i >=0; --i){
            for (int j = i + 1 ; j < M; ++j){
                if(name[i]==name[j])
                    dp[i][j] = dp[i+1][j-1];//如果i和j相同 就向内扣一个 不用任何操作
                else{
                    //如果不相同 要考虑四种修改方法 
                    dp[i][j] = 1<<30;
                    unsigned long long cs[4];
                    //注意 此时要保证 i+1,j 和 i,j-1都完成了 所以选择i降序 j升序
                    cs[0] = dp[i+1][j] + v[name[i]-'a'].add; // 先让i+1到j是回文的 再在最后加一个i 
                    cs[1] = dp[i+1][j] + v[name[i]-'a'].del; // 先让i+1到j是回文的 再把前面的i删掉 
                    cs[2] = dp[i][j-1] + v[name[j]-'a'].add; // 先让i到j-1是回文的 再在最前面加一个j 
                    cs[3] = dp[i][j-1] + v[name[j]-'a'].del; // 先让i到j-1是回文的 再在最后的j删掉
                    
                    for(int k = 0; k<4; ++k)
                        dp[i][j] = min(dp[i][j],cs[k]);
                }
            }
        }
        return dp[0][M-1];
    }
    int main(int argc, char const *argv[])
    {
        init();
        cout<<build()<<endl;
        return 0;
    }
  • 相关阅读:
    梯度提升树(GBDT)原理小结
    scikit-learn Adaboost类库使用小结
    集成学习之Adaboost算法原理小结
    集成学习原理小结
    支持向量机高斯核调参小结
    scikit-learn 支持向量机算法库使用小结
    支持向量机原理(五)线性支持回归
    支持向量机原理(四)SMO算法原理
    支持向量机原理(三)线性不可分支持向量机与核函数
    支持向量机原理(二) 线性支持向量机的软间隔最大化模型
  • 原文地址:https://www.cnblogs.com/yuchenlin/p/sjtu_oj_1066.html
Copyright © 2020-2023  润新知