[EOJ][382][Match Maker][KMP]
2011-04-27 23:44
183 查看
/* 题目:Match Maker 题目来源:EOJ 382 题目难度:中等偏难 题目内容:KMP(模糊匹配) 给出一个模板串和一系列待匹配串,长度小于等于100000。 模板串中含有的字符包括'0'-'9'、'*'、'#'。其中'*'匹配偶数个字符, '#'匹配奇数个字符;如"1*3",匹配"1223",不匹配"123"。存在连续多 个'*''#'时,匹配字符个数只看奇偶,如"1*#3"等价于"1#3","1**3"等 价于"1*3"。判断后面给出的字符串是否匹配模板串。 解题思路: 把模板串按'*''#'分割开来,并以'*''#'为前缀。比如"1212*34534#78" 分割为"1212"+"*34534"+"#78"。然后每一小段分别建立fail指针,建 fail指针时不必考虑'*''#'。待匹配串从第一小段开始一段段匹配,当 某段匹配成功时,还需要判断前缀是否符合'*''#'的奇偶性。当所有的 小段都匹配成功时,才算完全匹配。比如字符串"12121345345347887878" 匹配刚才的模板串 匹配方式: "1212" "*34534" "#78" "1212" "134534534" "7887878" 注意的细节: 给每一小段建立fail指针时,不需要开多个数组,只要用一个即可。 并且在最后一个字符的后面再建一个指针,这样匹配成功后判断出不符 合奇偶条件时可以继续匹配。 比如 模板串 :1 2 1 2 * 3 4 5 3 4 # 7 8 fail指针:0 1 1 2 3 0 1 1 1 2 3 0 1 1 另外,匹配的时候,先把首尾连续的数字串匹配掉,这样可以做到精确 匹配。比如"1212*34534#78"和"12121345345347887878"匹配的时候, 可能匹配的方式为 "1212" "*34534" "#78" "1212" "134534534" "78878" "78" 待匹配串多出了一个"78",这时就会判断为不能完全匹配 先把首尾的"1212"和"78"匹配掉,剩下"*34534#"和"13453453478878" 匹配时就不会有问题了。 做题日期:2011.4.27 */ #include <cstdio> #include <cstdlib> #include <climits> #include <iostream> #include <algorithm> #include <cstring> #include <string> #include <queue> #include <map> #include <vector> #include <bitset> #include <cmath> #include <set> #include <utility> #include <ctime> #define sqr(x) ((x)*(x)) using namespace std; const int N = 100010; char pat , str ; int fail ; int makefail(char *t, int fail[]) { --t; int i, j; for (i = 1, j = 0; isdigit(t[i]); ++i, ++j) { fail[i] = j; while (j > 0 && t[i] != t[j]) j = fail[j]; if (!isdigit(t[i + 1])) fail[i + 1] = j + 1; } return i; } int kmp(char *s, char *t, int fail[], int lim, int flag, int &x) { --s; --t; for (int i = 1, j = 1; s[i]; ++i, ++j) { while (j > 0 && s[i] != t[j]) j = fail[j]; if (!isdigit(t[j + 1])) { int z = i - j; if (z >= lim && z % 2 == flag) { x += j; return i; } j = fail[j + 1] - 1; } } return -1; } bool gao() { int lim, flag, i = 0, j = 0; int ls = strlen(str); int lt = strlen(pat); while (isdigit(pat[j])) if (str[i++] != pat[j++]) return false; while (j < lt && isdigit(pat[lt - 1])) if (str[--ls] != pat[--lt]) return false; while (j < lt) { for (lim = 0; j < lt && !isdigit(pat[j]); ++j) { lim += (pat[j] == '#' ? 1 : 2); //本来以为还有长度要求的 flag = lim & 1; } if (j == lt) return (ls - i) % 2 == flag; int t = kmp(str + i, pat + j, fail + j, 0, flag, j); if (t == -1) return false; i += t; } return ls - i == 0; } bool solve(int cas) { int id = 1; scanf("%s", pat); int len = strlen(pat); memset(fail, 0, sizeof(fail)); for (int i = 0; i < len; ) i += makefail(pat + i, fail + i); //for (int i = 1; i <= len + 1; ++i) // printf("%d ", fail[i]); //puts(""); while (scanf("%s", str)) { if (str[0] == 'E') return true; if (str[0] == 'Q') return false; printf("%d.%d. %s\n", cas, id++, gao() ? "match" : "not"); } return false; } int main(){ #ifndef ONLINE_JUDGE freopen("D:\\in.txt", "r", stdin); #endif int cas = 1; while (solve(cas++)); return 0; }
相关文章推荐
- ZOJ 3587 Marlon's String 扩展KMP
- 一些扩展kmp的总结
- hdu1867(kmp)
- poj3461 KMP模板 或 哈希
- 字符串匹配算法(KMP)
- POJ 3461 Oulipo(KMP裸题)
- KMP的理解
- 51NOD 1554 欧姆诺姆和项链 【kmp】
- KMP与BF模式匹配算法
- Best Reward (hdu 3613 拓展KMP)
- Period (poj 1961&&hdu 1358)KMP
- POJ2752 Seek the Name, Seek the Fame 解题报告【字符串】【KMP】
- HDU 3336 Count the string(kmp)
- KMP题目分析与总结
- 字符串匹配算法KMP
- KMP
- Hduoj1686 【KMP】
- HDU 6068 Classic Quotation KMP+DP
- 模式匹配的KMP 算法
- 【字符串入门专题1】J - Oulipo hdu1686 【kmp】