一道水题引发的错误(hdoj 1711)
之前对KMP一直处于朦胧期,看书能看懂,就是自己写不出来…今天在大神牛Matrix67的神的指示下,终于掌握(个人感觉)。贴上连接http://www.matrix67.com/blog/archives/115/。随手拿起以前在hdoj上的1711练手,哪知问题出现了。
其实这题很久以前就AC了,不过由于它要求的只是第一个匹配的位置,所以循环加strstr水过。而且貌似效率比KMP还要高…下面贴上错误的KMP代码
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #define UNLOCAL 5 #define MAXM 10000 + 10 6 #define MAXN 1000000 + 10 7 char a[MAXN], b[MAXM], temp[MAXN]; 8 9 int kmp(char *d, char *s); 10 int main() 11 { 12 #ifdef LOCAL 13 freopen("data.in", "r", stdin); 14 #endif // LOCAL 15 int T, M, N; 16 int i, j, t; 17 scanf("%d", &T); 18 while(T--) 19 { 20 memset(a, sizeof(a), '\0'); 21 memset(b, sizeof(b), '\0'); 22 memset(temp, sizeof(temp), '\0'); 23 scanf("%d%d", &M, &N); 24 getchar(); 25 gets(temp); 26 t = strlen(temp), j = 0; 27 a[j++] = ' '; 28 for(i=0; i<t; ++i) 29 { 30 if(temp[i] != ' ') 31 a[j++] = temp[i]; 32 } 33 #ifdef LOCAL 34 printf("%s\n", a); 35 #endif 36 memset(temp, sizeof(temp), '\0'); 37 gets(temp); 38 t = strlen(temp), j = 0; 39 b[j++] = ' '; 40 for(i=0; i<t; ++i) 41 { 42 if(temp[i] != ' ') 43 b[j++] = temp[i]; 44 } 45 #ifdef LOCAL 46 printf("%s\n", b); 47 #endif 48 printf("%d\n", kmp(a, b)); 49 } 50 return 0; 51 } 52 53 int kmp(char *d, char *s) 54 { 55 int ns = strlen(s), nd = strlen(d); 56 int i, j; 57 int p[MAXM]; 58 p[1] = 0, j = 0; 59 for(i=2; i<ns; ++i) 60 { 61 while(j>0 && s[i]!=s[j+1]) 62 j = p[j]; 63 if(s[i] == s[j+1]) 64 ++ j; 65 p[i] = j; 66 } 67 #ifdef LOCAL 68 for(i=1; i<ns; ++i) 69 { 70 printf("%d ", p[i]); 71 } 72 printf("\n"); 73 #endif // LOCAL 74 j = 0; 75 for(i=1; i<nd; ++i) 76 { 77 while(j>0 && d[i]!=s[j+1]) 78 j = p[j]; 79 if(d[i] == s[j+1]) 80 ++ j; 81 if(j == ns-1) 82 return i-j+1; 83 } 84 return -1; 85 }
提交,刷新,竟然出现Runtime Error (ACCESS_VIOLATION)...
把MAXN, MAXM扩大10倍后,再提交,刷新,哎,错误不见了,但是Wrong Answer..前前后后又做了若干修改,但是就是不能AC...
其实这题从算法选择上没有问题,问题仅仅在于,不应该用字符串一次输入。这将导致两个问题,第一当输入的每个数很大时,会占用很多字节来存放一个int,这就是为什么会Runtime Error (ACCESS_VIOLATION),第二,当成字符串后,比如两个输入:A(12 23)和B(2 23),其实B并不是A的子序列,但是转换成字符串后,A等价于A'(1223),而B等价于B'(223),然而B'是A'的字符串,自然会Wrong Answer。
好了,现在贴上修改后的代码:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #define UNLOCAL 5 #define MAXN 1000000 + 10 6 #define MAXM 10000 + 10 7 int a[MAXN], b[MAXM], p[MAXM]; 8 9 int kmp(int s[], int d[], int ns, int nd); 10 int main() 11 { 12 int T, N, M; 13 int i; 14 #ifdef LOCAL 15 freopen("data.in", "r", stdin); 16 #endif // LOCAL 17 scanf("%d", &T); 18 while(T--) 19 { 20 memset(a, sizeof(a), 0); 21 memset(b, sizeof(b), 0); 22 scanf("%d%d", &N, &M); 23 for(i=1; i<=N; ++i) 24 scanf("%d", &a[i]); 25 for(i=1; i<=M; ++i) 26 scanf("%d", &b[i]); 27 #ifdef LOCAL 28 for(i=1; i<=N; ++i) 29 printf("%d", a[i]); 30 printf("\n"); 31 for(i=1; i<=M; ++i) 32 printf("%d", b[i]); 33 printf("\n"); 34 #endif // LOCAL 35 printf("%d\n", kmp(b, a, M, N)); 36 } 37 return 0; 38 } 39 40 int kmp(int s[], int d[], int ns, int nd) 41 { 42 int i, j; 43 memset(p, sizeof(p), 0); 44 p[1] = 0, j = 0; 45 for(i=2; i<=ns; ++i) 46 { 47 while(j>0 && s[j+1]!=s[i]) 48 j = p[j]; 49 if(s[j+1] == s[i]) 50 ++ j; 51 p[i] = j; 52 } 53 j = 0; 54 for(i=1; i<=nd; ++i) 55 { 56 while(j>0 && d[i]!=s[j+1]) 57 j = p[j]; 58 if(d[i] == s[j+1]) 59 ++ j; 60 if(j == ns) 61 return i-j+1; 62 } 63 return -1; 64 }