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 }

 

posted @ 2020-07-27 20:11  programmer_w  阅读(0)  评论(0)    收藏  举报