zoukankan      html  css  js  c++  java
  • 「Luogu P1435」回文字串 解题报告

    题面

    主要大衣大意:

    给定一个字符串,求至少加入多少个字符才能使字符串变成回文字符串

    下面就是我一本正经的胡说八道题解

    思路:

    很显然,这应该是一道典型的最长公共子序列的题目

    因此,主要思想就是DP

    方程式也挺好推的

    于是我们就来讲一下为什么这题能用最长公共子序列(LCS)求解

    证明:

    求的是什么?

    想要使这个字符串加入最少的字符变成一个回文串,那么肯定就是要是字符串中不能回文的部分回文

    说起来比较难理解,比如:Ab3bd最少添的字符就是A对应的一个A,最后d对应的一个d

    我们可以发现,最少要添的字符就是不能匹配的字符数=原字符串长度len-最长回文串的长度

    这就变成了求最长回文串的题目

    怎么求?

    又经验的人肯定就会用最长公共子序列去解,但是一些人可能要问为什么,那么我们这里就来证明一下

    由于回文串是回文的(废话),也就是说,把原来的字符串反转一遍,最长回文串的长度还是不变

    于是我们就变成了求两串的公共子序列的长度——其实思想就是回文串正着和反着的效果是一样的,也就是抓住这个特性,去求公共系序列的长度

    转移方程(最好自己去推一下):

    if(a[i]==b[j])//目标状态是f[len][len]
    	f[i][j]=f[i-1][j-1]+1;//表示i,j两位置相等,那么就由i-1,j-1的状态(最优解)+1得到
    else
    	f[i][j]=max(f[i-1][j],f[i][j-1]);//否则去掉i或j,转移最优解
    

    Code:

    #include<bits/stdc++.h>
    #define N 1010
    using namespace std;
    int len;
    char a[N],b[N];
    int f[N][N];
    int main()
    {
        int i,j;
        scanf("%s",a+1);
        len=strlen(a+1);
        for(i=1;i<=len;i++)
            b[i]=a[len-i+1];//反转
        for(i=1;i<=len;i++)
            for(j=1;j<=len;j++)
                if(a[i]==b[j])
                    f[i][j]=f[i-1][j-1]+1;
                else
                    f[i][j]=max(f[i-1][j],f[i][j-1]);
        printf("%d",len-f[len][len]);//长度减去最长回文串长度
        return 0;
    }
    

    拓展知识:

    最长上升子序列(LIS)

    推荐题目(进阶,就是比较难的意思):

    【模板】最长公共子序列

  • 相关阅读:
    RRC Server安装配置过程
    开园啦~
    VB.NET 初涉线程的定义和调用
    使用 VB.NET 开发多线程
    多线程 与 单线程 的区别
    Marshal 类的内存操作的一般功能
    VB.NET 内存指针和非托管内存的应用
    OpenProcess() 函数
    DataTable与结构不同实体类之间的转换
    C#的同步和异步调用方法
  • 原文地址:https://www.cnblogs.com/hovny/p/10171998.html
Copyright © 2011-2022 走看看