Hdu 1686 Oulipo
Problem地址:http://acm.hdu.edu.cn/showproblem.php?pid=1686
字符串匹配,因此采用了KMP算法。有一点需要注意,请看题目的样例2:
T: AZA
S: AZAZAZ
很明显T和S的前3位匹配,那么接下来呢?
我最初设计的程序,T和S的前三位匹配后,T开始与S的第四位进行匹配判断。
但实际上,S的第三位至S的第五位可以与T匹配。
为什么会这样呢?
我思考了之后明白了问题所在:当T在S中找到一个匹配串后,T将第一位与S的下一位进行比较。这实际上可能造成失去发现一个新字符串匹配的机会。
因此,当T在S中找到一个匹配串后,T不应将第一位与S的下一位进行比较。那应该将T的第几位比呢?其实思考一下就可以知道怎么办。
将T与自己匹配,当比较结束后,看一下作为待匹配的T最多与模式串T的第几位匹配即可。
#include <iostream> #include <cstring> #include <cstdio> using namespace std; const int W_MAXN = 10000 + 50; char word[ W_MAXN ]; int next[ W_MAXN ]; const int T_MAXN = 1000000 + 50; char text[ T_MAXN ]; int End; void Get_next() // 得到next数组 { int i, j = 0; next[ 1 ] = 0; int length = strlen( word+1 ); for( i=2;i<=length;i++ ) { next[i] = j; if( word[i]!=word[ j+1 ] ) { j = next[ j+1 ]; } else { j ++; } } } void Get_End() { int i, j = 0; int finish = strlen ( word+1 ); for( i=2; i<=finish;i++ ) { while( j>0 && word[i]!=word[j+1] ) { j = next[ j+1 ]; } if( word[i]==word[j+1] ) { j ++; } } End = j; } int Count() { int counter = 0; int i, j = 0; int finish = strlen ( word+1 ); int length = strlen ( text+1 ); for( i=1;i<=length;i++ ) { while( j>0 && text[i]!=word[ j+1 ] ) { j = next[ j+1 ]; } if( text[i] == word[j+1] ) { j ++; } if( j==finish ) { j = End; // 不应 j = 0 counter ++; } } return counter; } int main() { int T; scanf( "%d", &T ); while( T-- ) { scanf( "%s", word+1 ); scanf( "%s", text+1 ); // 为方便, 均从第一位读起 Get_next(); Get_End(); printf( "%d\n", Count() ); } return 0; }