zcmu-1661- 近似回文词

A - 近似回文词

输入一行文本,输出最长近似回文词连续子串。所谓近似回文词是指满足以下条件的字符串:

1. S以字母开头,字母结尾

2. a(S)和b(S)最多有2k个位置不同,其中a(S)是S删除所有非字母字符并且把所有字母转化成小写之后得到的串,b(S)是a(S)的逆序串。

比如当k=1时,Race cat是一个近似回文词,因为a(S)=racecat和b(S)=tacecar只有2个位置不同。

Input

输入包含不超过25组数据,每组数据包含两行。第一行是整数k(0<=k<=200),第二行为字符串S,包含至少一个字母但不超过1000个字符(换行符不算)。S只包含字符、空格和其他可打印字符(比如逗号,句号),并且不会以空白字符开头。

Output

对于每组测试数据,输出最长近似回文子串的长度和起始位置(S的第一个字符是位置1)。如果有多个最长近似回文子串解,起始位置应尽量小。

Sample Input
1Wow, it is a Race cat!0abcdefg0Kitty: Madam, I'm adam.
Sample Output
Case 1: 8 3Case 2: 1 1Case 3: 15 8

Hint

这道题我刚开始的想法就是硬搜,然后不出意外的超时了。然后优化了一下双向搜索过了......(他要求显示的位置是原来的位置这是一个坑.....专门开了一个数组来记录)

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
int main()
{
    char pt[2000],s[2000];
    int ss[2000];
    int n,m,q,x,y,t=1,k,flag,f,ans,sum;
    while(~scanf("%d\n",&k))
    {
        flag=0;ans=0;x=0;
        gets(pt);
        int len=strlen(pt);
        for(int i=0;i<len;i++){
            if(isalpha(pt[i])){//判断是不是字母;
                ss[flag]=i;//记录位置
                s[flag]=toupper(pt[i]);//转换成小写的;
                flag++;
            }
        }
        int j=0;
        for(int i=0;i<flag;i++){
            sum=0;//记录有几个不同
            for(j=0;i-j>=0&&i+j<flag;j++){
                if(s[i-j]!=s[i+j])sum++;
                if(sum>k)break;
            }
            j--;//因为超出的时候输出j,所以j要减1;
            if(ss[i+j]-ss[i-j]+1>ans){
                ans=ss[i+j]-ss[i-j]+1;
                x=ss[i-j];
            }//偶数个的情况
            sum=0;
            for(j=0;i-j>=0&&i+j+1<flag;j++){
                if(s[i-j]!=s[i+j+1])sum++;
                if(sum>k)break;
            }
            j--;
            if(j<=-1)continue;
            if(ss[i+j+1]-ss[i-j]+1>ans){
                ans=ss[i+j+1]-ss[i-j]+1;
                x=ss[i-j];
            }
        }
        printf("Case %d: %d %d\n",t++,ans,x+1);
    }
    return 0;
}


猜你喜欢

转载自blog.csdn.net/qibage/article/details/77340161