poj1816 字典树+DFS
模糊匹配,注意模式串小标从0开始。
1 #include<algorithm> 2 #include<cstdio> 3 #include<iostream> 4 #include<queue> 5 #include<vector> 6 #include<map> 7 #include<stack> 8 #include<string> 9 #include<cmath> 10 #include<cstring> 11 #include<sstream> 12 #include<set> 13 using namespace std; 14 typedef long long int ll; 15 typedef unsigned long long int ull; 16 inline int rd() { 17 int X = 0, w = 0;char ch = 0;while (!isdigit(ch)) { w |= ch == '-';ch = getchar(); } 18 while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();return w ? -X : X; 19 } 20 #define bug puts("DEBUG*******************************") 21 #define in(a) int n = rd() 22 #define pi acos(-1) 23 #define pb push_back 24 #define rep(i,a,n) for(int i=a;i<=n;++i) 25 #define per(i,a,n) for(int i=a;i>=n;--i) 26 #define sld(n) scanf("%lld",&n) 27 #define sldd(n,m) scanf("%lld %lld",&n,&m) 28 #define pd(n) printf("%d\n",n) 29 #define pld(n) printf("%lld\n",n) 30 #define mem(a,b) memset(a,b,sizeof a) 31 #define Case(T) int T=rd();while(T--) 32 #pragma comment(linker, "/STACK:102400000,102400000") 33 const double eps = 1e-8; 34 const int inf = 0x3f3f3f3f; 35 const ll INF = 0x3f3f3f3f3f3f3f3f; 36 const int MOD = 10007; 37 const int maxn = 1e5 + 10; 38 int tot = 0; 39 int pos[maxn],vis[maxn]; 40 int sum[maxn], exist[maxn]; 41 int trietree[maxn][30]; 42 //字符串数量为n,字符串最大长度为len,maxn=n*len 43 int insert(string s) {//插入 44 int len = s.length(); 45 int root = 0; 46 for (int i = 0; i < len; ++i) { 47 int id; 48 if (s[i] == '?')id = 26; 49 else if (s[i] == '*')id = 27; 50 else id = s[i] - 'a'; 51 if (trietree[root][id] == 0) { 52 trietree[root][id] = ++tot; //tot是新建的节点编号,从1开始 53 exist[root] = 0; 54 } 55 root = trietree[root][id]; 56 sum[root] ++; //表示有相同该前缀的单词个数 57 } 58 //root 最终储存该字符串的位置 59 exist[root] = 1;//该节点是存入的单词最后一位,表示该单词是插入的,不只是某个单词的前缀 60 return root; 61 } 62 void dfs(string a, int rot, int pos) { 63 if (pos == a.length() && exist[rot]) {//枚举到最后并且这个单词确实出现过 64 vis[rot] = 1;//长度相等,且以此结尾的字符串必定匹配成功,因为?,*均可匹配一个字符,若为原配更是可以。 65 } //不直接return 因为*可以不匹配字符 所以还可能存在可匹配的字符串,例如:t*****,t***,t*,return只有一个解 66 int root = rot; 67 int id = a[pos] - 'a'; 68 if (trietree[root][id]) {//如果这个字符是小写字母,继续搜下去 69 int temp = trietree[rot][id]; 70 dfs(a, temp, pos + 1);//temp该节点之下去寻找下一个,例如:搜到abcd,在第四层d节点继续寻找目标串 71 } 72 if (trietree[root][26]) //如果是“?”同小写字母 73 { 74 int temp = trietree[root][26]; 75 dfs(a, temp, pos + 1);//默认匹配 76 } 77 if (trietree[root][27]) { //如果是“*”特殊处理 78 int temp = trietree[root][27]; 79 for (int i = pos; i <= a.length(); i++)//*可匹配任意数量字符包括0 所以从pos开始枚举到最后 80 dfs(a, temp, i);//默认匹配多个 81 } 82 } 83 int main() { 84 int n = rd(), m = rd(); 85 string s; 86 rep(i, 0, n-1) { 87 cin >> s; 88 pos[i]=insert(s); 89 } 90 while (m--) { 91 mem(vis, 0); 92 cin >> s; 93 dfs(s, 0, 0); 94 int flag = 0; 95 for (int i = 0; i < n; i++) 96 if (vis[pos[i]])cout << i << " ", flag = 1; 97 if (flag == 0) cout << "Not match"; 98 puts(""); 99 } 100 }