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 int j=0,k=-1; 11 next[0]=-1; 12 while(j<len){ 13 if(k==-1||str[j]==str[k]) next[++j]=++k; 14 else k=next[k]; 15 } 16 } 17 18 //返回串S中第一次出现串T的开始位置 19 int KMP(char *S,char *T){ 20 int l1=strlen(S), l2=strlen(T); 21 int i=0,j=0; 22 while(i<l1){ 23 if(j==-1||S[i]==T[j]) 24 i++, j++; 25 else j=next[j]; 26 if(j==l2) return i-l2+1; 27 } 28 return -1;//若一直不匹配则返回-1 29 } 30 31 int main(){ 32 int T,n; 33 scanf("%d", &T); 34 while(T--){ 35 memset(ans,0,sizeof(ans)); 36 scanf("%d", &n); 37 for(int i=0;i<n;i++) scanf("%s", str[i]); 38 39 for(int i=0; i<strlen(str[0]); i++)//把第一个串的每一个子串当作模板串,求next数组,并和后面的每一个串去匹配 40 for(int j=i+2; j<strlen(str[0]); j++){ 41 char s[65]; 42 strncpy(s, str[0] + i, j - i + 1);///strncpy 43 s[j - i + 1] = '\0'; 44 getnext(s); 45 46 int flag = 1; 47 for(int k = 1; flag&&k < n; k++) 48 if(KMP(str[k], s)==-1) 49 flag = 0; 50 ///匹配成功,判长度和字典序 51 if(flag&& ( strlen(s)>strlen(ans) || ( strlen(s)==strlen(ans)&&strcmp(s, ans)<0))) 52 strcpy(ans, s); 53 } 54 55 if(strlen(ans) < 3) puts("no significant commonalities"); 56 else puts(ans); 57 } 58 return 0; 59 }
题目: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 next[MAXN]; 9 void getnext(char *str){ 10 int len=strlen(str); 11 int j=0,k=-1; 12 next[0]=-1; 13 while(j<len){ 14 if(k==-1||str[j]==str[k]) next[++j]=++k; 15 else k=next[k]; 16 } 17 } 18 19 int KMP(char *S,char *T){//返回S中出现T的次数 20 int l1=strlen(S), l2=strlen(T); 21 int ans=0,i=0,j=0; 22 while(i<l1){ 23 if(j==-1||S[i]==T[j]) 24 i++, j++; 25 else j=next[j]; 26 if(j==l2) ans++; 27 } 28 return ans; 29 } 30 int main(){ 31 int T; scanf("%d",&T); 32 while(T--){ 33 scanf("%s%s",t,s); 34 getnext(t);//获得第一个串的next数组去匹配第二个串 35 printf("%d\n",KMP(s,t)); 36 } 37 return 0; 38 }
Stay Hungry, Stay Foolish