一道水题引发的错误(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 }
View Code

 

  提交,刷新,竟然出现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 }
View Code

 

转载于:https://www.cnblogs.com/focuXer/p/3475330.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值