密码脱落 C++

题目描述

X星球的考古学家发现了一批古代留下来的密码。 这些密码是由几种植物的种子串成的序列。植物种类由26个大写英文字母表示,即最多有26种植物。 仔细分析发现,这些密码串当初应该是前后对称的(也就是我们说的镜像串)。 由于年代久远,其中许多种子脱落了,因而可能会失去镜像的特征。

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

输入格式:

输入一行,表示现在看到的密码串(长度不大于1000)

输出格式:

要求输出一个正整数,表示至少脱落了多少个种子。

输入样例:
在这里给出一组输入。例如:

ABCBA

输出样例:
在这里给出相应的输出。例如:
0

输入样例:
在这里给出一组输入。例如:
ABDCDCBABC

输出样例:
在这里给出相应的输出。例如:
3

参考代码

这里给出一种动态规划的做法,要求原来的序列,即先求出与倒序的字符串匹配的最长子序列长度(匹配了就说明对称),然后用字符串总长度减去最长公共子序列即可。

#include <cstdio>
#include <iostream> 
#include <algorithm>
#include <cmath>
#include <cstring>
#include <map>
#include <queue>
#include <stack>

using namespace std;

#define N_MAX 1000

char a[N_MAX+5];
char b[N_MAX+5];
int dp[N_MAX+5][N_MAX+5];

void print()
{ 
    int k1=1;
    
    cout<<"  ";
    for(k1 = 1;k1<=9;k1++)
    {
        cout<< k1 <<" ";
    }
    cout << endl;
    
    for(int i = 1;i<=9;i++)
    {
        cout << i << " ";
        for(int j = 1;j<=9;j++)
        {
            cout << dp[i][j] << " ";
        }
        cout <<endl; 
    }
    
    cout << "--------------------"<<endl;
}

int main()
{
    freopen("test.in","r",stdin);
    //freopen("test.out","w",stdout);
    int i,j;
    int len;
    
    //memset(dp,1,sizeof(dp));
    
    scanf("%s",a+1);
    
    len = strlen(a+1);

    for(i = 1;i<=len;i++)
    {
        b[i] = a[len-i+1];
    }
    
    b[len+1] = 0;
    
    for(i = 1;i<=len;i++)
    {
        for(j = 1;j<=len;j++)
        {
            if(a[i]==b[j])
                dp[i][j] = dp[i-1][j-1] + 1;
            else
                dp[i][j] = max(dp[i-1][j],dp[i][j-1]);
            //print();
        }
    }
    
    cout << len - dp[len][len];
    
    return 0;
}

一种错误的做法

在这里有必要指出一种基于贪心的做法,这是错误的。

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

using namespace std;

char str1[1005],str2[1005]; 

int main()
{
    freopen("test.in","r",stdin);
    //freopen("test.out","w",stdout);
    int head,tail;
    int count_ = 0;
    
    cin >> str1;
    
    head = 0;
    tail = strlen(str1) - 1;
    while(head<tail)
    {
        while(str1[head]==str1[tail]&&head<tail)
        {
            head++;
            tail--;
        }
        if(head==tail)
            break;
        count_++; 
        tail--;
    }
    cout << count_;
    
    return 0;
}

为什么会出错?

贪心是每一步取当前最优,推出全局最优,且没有后效性。
在这个示例中,可以发现:

1.使用前后指针匹配,认为“在前指针head指向的每一个字母必须先和后指针tail指向的字母匹配,否则tail–”
2.每一个字母使用后不能再次使用,因此可能会错过最优值
3.仅一次局部最优非全局最优
4.如何优化这种做法?多次轮流匹配以求最优。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值