【USACO】calfflac

关键:以回文中心位置为变量进行遍历


//必须把纯字母先提出来 否则肯能会出现错误 比如: lvlv= 在检查长度4时 lvlv认为不是回文 vlv=认为是回文 但实际上 lvl 出现的要更早一些

//判断回文的方法 可以输入字符串后 左右比较 或者分别正序 逆序 存储 判断是否相等

//我的思路不对 严重超时了 我是以长度为变量进行循环  对于每个长度 每一个不同起始点的序列都需要对 整个序列重新判断一次是否为回文 O(n^3)

//答案中 以中心字母为变量进行循环 只需要对每一个字母做为中心变量遍历一次, 每次的遍历长度小于等于总序列长度  通过不断更新存储最长回文找到最优解 O(n^2)

#include <stdio.h>

#include <string.h>

#include <ctype.h>

typedef struct

{

    char c;

    int n;

}AZ;



int isch(char c)

{

    return ((c <= 'z' && c >= 'a') || (c >= 'A' && c <= 'Z'));

}

int iscalfflac(AZ *c, int l, int r, int * loc) //输入字符 和 左右边界 判断是否为回文

{

    int len = r - l + 1;

    int ll, rr;

    int flag = 1;

    int is = 0; //判断是否进入过相等 防止纯符号

    while(l <= r)

    {

        if(c[l].c == c[r].c || c[l].c == c[r].c - 'A' + 'a' || c[r].c == c[l].c - 'A' + 'a')

        {

            l++; r--; is++;

        }

        else

        {

            flag = 0;break;

        }

    }

    return (flag == 1) ? 1 : 0;

}

int main()

{

    FILE *in, *out;

    int loc[4] = {0,0,0,0};

    int i = 0, j = 0, length;

    int r, l, rr, ll;

    char c[20000], c1[20000], c2[20000], c3[20000], c4[20000];

    AZ ch[20000];

    in = fopen("calfflac.in", "r");

    out = fopen("calfflac.out", "w");

    while(fscanf(in, "%c", &c[i]) != EOF)

    {

        if(isch(c[i]))

        {

            ch[j].c = c[i];

            ch[j].n = i;

            j++;

        }

        i++;

    }

    length = j; //总输入长度

    for(i = 0; i < length; i++)

    {

        if(isupper(ch[i].c))

        {

            ch[i].c = ch[i].c - 'A' + 'a';

        }

        c1[i] = ch[i].c;

        c2[length - i - 1] = ch[i].c;

    }



    for(i = length; i > 0; i--) //这种方法在大输入时严重超时了

    {

        for(l = 0; l <= length - i; l++ )

        {

            r = l + i - 1;

            if(iscalfflac(ch, l, r, loc) == 1)

            {

                fprintf(out, "%d\n", i);

                for(j = ch[l].n ; j <= ch[r].n; j++)

                {

                    fprintf(out, "%c", c[j]);

                }

                fprintf(out, "\n");

                return 0;

            }

        }

    }

    fprintf(out, "%d\n", 0);

    return 0;

}

 

下面是答案的,注意做中心点时要对 奇数 偶数 考虑齐全

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <assert.h>

#include <ctype.h>



char fulltext[21000];

char text[21000];



char *pal;

int pallen;



void

findpal(void)

{

    char *p, *fwd, *bkwd, *etext;

    int len;



    etext = text+strlen(text);

    for(p=text; *p; p++) {

    /* try palindrome with *p as center character */

    for(fwd=bkwd=p; bkwd >= text && fwd < etext && *fwd == *bkwd;

                fwd++, bkwd--)

            ;

    bkwd++;

    len = fwd - bkwd;

    if(len > pallen) {

        pal = bkwd;

        pallen = len;

    }



    /* try palindrome with *p as left middle character */

    for(bkwd=p, fwd=p+1;

              bkwd >= text && fwd < etext && *fwd == *bkwd; fwd++, bkwd--)

            ;

    bkwd++;

    len = fwd - bkwd;

    if(len > pallen) {

        pal = bkwd;

        pallen = len;

    }

    }

}



void

main(void)

{

    FILE *fin, *fout;

    char *p, *q;

    int c, i, n;



    fin = fopen("calfflac.in", "r");

    fout = fopen("calfflac.out", "w");

    assert(fin != NULL && fout != NULL);



    /* fill fulltext with input, text with just the letters */

    p=fulltext;

    q=text;

    while((c = getc(fin)) != EOF) {

    if(isalpha(c))

        *q++ = tolower(c);

    *p++ = c;

    }

    *p = '\0';

    *q = '\0';



    findpal();



    fprintf(fout, "%d\n", pallen);



    /* find the string we found in the original text

       by finding the nth character */

    n = pal - text;

    for(i=0, p=fulltext; *p; p++)

    if(isalpha(*p))

        if(i++ == n)

        break;

    assert(*p != '\0');



    /* print out the next pallen characters */

    for(i=0; i<pallen && *p; p++) {

    fputc(*p, fout);

    if(isalpha(*p))

        i++;

    }

    fprintf(fout, "\n");



    exit(0);

}

 

 

你可能感兴趣的:(USACO)