【蓝桥杯】密码脱落

密码脱落

X星球的考古学家发现了一批古代留下来的密码。这些密码是由A、B、C、D 四种植物的种子串成的序列。仔细分析发现,这些密码串当初应该是前后对称的(也就是我们说的镜像串)。由于年代久远,其中许多种子脱落了,因而可能会失去镜像的特征。

你的任务是:
  给定一个现在看到的密码串,计算一下从当初的状态,它要至少脱落多少个种子,才可能会变成现在的样子。

输入一行,表示现在看到的密码串(长度不大于1000)
  要求输出一个正整数,表示至少脱落了多少个种子。

例如,输入:

ABCBA

则程序应该输出:

0

再例如,输入:

ABECDCBABC

则程序应该输出:

3

思路

  • 这道题考思维,懂了之后一下就懂了,但是没想到思路之前却很难
  • 所以记录下来当做模板
  • 总之,就是一个求最长公共子序列的模板
  • 最后要补的字符个数就是字符串长度减去这个字符串和自己翻转之后得到的字符串的最长公共子序列的长度

怎么求两个字符串的最长公共子序列?

  • DP
  • d p [ i ] [ j ] dp[i][j] dp[i][j] 表示第一个字符串的前面 i i i 个字符和第二个字符串前面的 j j j 个字符的最长公共子序列的长度
  • 初始化: d p [ 0 ] [ j ] = 0 , d p [ i ] [ 0 ] = 0 dp[0][j]=0,dp[i][0]=0 dp[0][j]=0dp[i][0]=0 i i i j j j 的下标都从1开始
  • d p [ i ] [ j ] = { d p [ i − 1 ] [ j − 1 ] + 1 , s t r 1 [ i ] = = s t r 2 [ j ] m a x ( d p [ i − 1 ] [ j ] , d p [ i ] [ j − 1 ] ) , s t r 1 [ i ] ! = s t r 2 [ j ] dp[i][j]=\left\{ \begin{aligned} dp[i-1][j-1]+1,{str1[i]==str2[j]}\\ max(dp[i-1][j],dp[i][j-1]),{str1[i]!=str2[j]} \end{aligned} \right. dp[i][j]={dp[i1][j1]+1,str1[i]==str2[j]max(dp[i1][j],dp[i][j1]),str1[i]!=str2[j]

代码如下

#include 
#include 
using namespace std;
const int N = 1001;

char str[N];
int dp[N][N];

void solve() {
    scanf("%s", str);
    int len = strlen(str);
    int i = 0, j = 0;
    for (i = 0; i < len; i++) {
        for (j = 0; j < len; j++) {
        	//说是翻转,但是也不必真的翻转,只需要变一下下标即可
            if (str[i] == str[len - 1 - j]) {
            	//如果两个字符相等,则该位置填其左上角位置的数+1
                dp[i + 1][j + 1] = dp[i][j] + 1;
            } else {
            	//否则就是上面的位置和左边位置的最大值
                dp[i + 1][j + 1] = max(dp[i][j + 1], dp[i + 1][j]);
            }
        }
    }
    printf("%d\n", len - dp[len][len]);
}

int main(void) {
    solve();
    return 0;
}

你可能感兴趣的:(蓝桥杯,动态规划,算法)