您的位置:首页 > 其它

[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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: