【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); }