POJ 3080 Blue Jeans、POJ 3461 Oulipo——KMP应用

题目:POJ3080 http://poj.org/problem?id=3080

题意:对于输入的文本串,输出最长的公共子串,如果长度相同,输出字典序最小的。

这题数据量很小,用暴力也是16ms,用后缀数组可以到0ms,但我不会XD。

暴力:

 1 #include<cstdio>
 2 #include<cstring>
 3 using namespace std;
 4 char str[15][65],ans[65];
 5 int main(){
 6     int T,n;  scanf("%d", &T);
 7     while (T--){
 8         memset(ans,0,sizeof(ans));
 9         scanf("%d", &n);
10         for (int i = 0; i < n; i++)  scanf("%s", str[i]);
11 
12         for (int i = 0; i < strlen(str[0]); i++)
13             for (int j = i + 2; j < strlen(str[0]); j++){
14                 char s[65];//子串
15                 strncpy(s, str[0] + i, j - i + 1);///strncpy
16                 s[j - i + 1] = '\0';
17 
18                 int flag = 1;
19                 for (int k = 1; flag && k < n; k++)
20                     if (strstr(str[k], s) == NULL)
21                         flag = 0;
22                 ///匹配成功,判长度和字典序
23                 if (flag && (j - i + 1 > strlen(ans) || (j - i + 1 == strlen(ans)&&strcmp(ans, s)>0) ) )
24                     strcpy(ans, s);
25             }
26 
27         if (strlen(ans) < 3)  puts("no significant commonalities");
28         else  puts(ans);
29     }
30     return 0;
31 }

KMP:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 using namespace std;
 5 char str[15][65],ans[65];
 6 int next[65];
 7 //计算串str的next数组
 8 void getnext(char *str){
 9     int len=strlen(str);
10     next[0]=next[1]=0;
11     for(int i=1;i<len;i++){
12         int j=next[i];
13         while(j&&str[i]!=str[j]) j=next[j];//一直回溯j直到str[i]==str[j]或j减小到0
14         next[i+1]=str[i]==str[j]?j+1:0;//更新next[i+1]
15     }
16 }
17 //返回值是串S中第一次出现串T的开始位置
18 int KMP(char *S,char *T){
19     int l1=strlen(S),l2=strlen(T);
20     int j=0;
21     for(int i=0;i<l1;i++){
22         while(j&&S[i]!=T[j]) j=next[j];
23         if(S[i]==T[j]) j++;
24         if(j==l2) return i-l2+1;
25     }
26     return -1;//若一直匹配不成功则返回-1
27 }
28 
29 int main(){
30     int T,n;
31     scanf("%d", &T);
32     while(T--){
33         memset(ans,0,sizeof(ans));
34         scanf("%d", &n);
35         for(int i=0;i<n;i++)  scanf("%s", str[i]);
36 
37         for(int i=0; i<strlen(str[0]); i++)//把第一个串的每一个子串当作模板串,求next数组,并和后面的每一个串去匹配
38             for(int j=i+2; j<strlen(str[0]); j++){
39                 char s[65];
40                 strncpy(s, str[0] + i, j - i + 1);///strncpy
41                 s[j - i + 1] = '\0';
42                 getnext(s);
43 
44                 int flag = 1;
45                 for(int k = 1; flag&&k < n; k++)
46                     if(KMP(str[k], s)==-1)
47                         flag = 0;
48                 ///匹配成功,判长度和字典序
49                 if(flag&& ( strlen(s)>strlen(ans) || ( strlen(s)==strlen(ans)&&strcmp(s, ans)<0)))
50                         strcpy(ans, s);
51             }
52 
53         if(strlen(ans) < 3)   puts("no significant commonalities");
54         else  puts(ans);
55     }
56     return 0;
57 }

题目:POJ3461 http://poj.org/problem?id=3461

题意:求第一个串在第二个串中出现的次数

 1 //第一个串在第二个串中出现的次数
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cstdio>
 5 using namespace std;
 6 #define MAXN 1000050
 7 char s[MAXN],t[MAXN];
 8 int l1,l2;
 9 int next[MAXN];
10 void getnext(){
11     int j=0,k=-1;
12     next[0]=-1;
13     while(j<l2){
14         if(k==-1||t[j]==t[k]) next[++j]=++k;
15         else k=next[k];
16     }
17 }
18 int kmpcount(){
19     int ans=0,i=0,j=0;
20     getnext();
21     while(i<l1){
22         if(j==-1||s[i]==t[j])
23             i++, j++;
24         else j=next[j];
25         if(j==l2)
26             ans++, j=next[j];
27     }
28     return ans;
29 }
30 int main(){
31     int T;  scanf("%d",&T);
32     while(T--){
33         scanf("%s%s",t,s);
34         l1=strlen(s);
35         l2=strlen(t);
36         printf("%d\n",kmpcount());
37     }
38     return 0;
39 }

猜你喜欢

转载自www.cnblogs.com/noobimp/p/10341435.html