zoukankan      html  css  js  c++  java
  • uva 11019 Matrix Matcher

    题意:给出一个n*m的字符矩阵T,你的任务是找出给定的x*y的字符矩阵P在T中出现了多少次.

    思路:要想整个矩阵匹配,至少各行都得匹配。所以先把P的每行看做一个模式串构造出AC自动机,然后在T中的各行逐一匹配,找到P中每一行的所有匹配点。

    只要在匹配时做一些附加操作,就可以把匹配出来的单一的行拼成矩形。用一个count[r][c]表示T中一(r,c)为右上角,与P等大的矩形中有多少个 完整的行和P对应位置的行完全相同.当P的第i行出现在T的第r行,起始列编号为c时,意味着count[r-i][c]应当加1.所有匹配结束后,count[r] [c]=X的那些就是一个二维匹配点.

    注意:模式串有可能相同,因此需要一个next数组来记录相同的模式串.

      1 #include<iostream>
      2 #include<string>
      3 #include<algorithm>
      4 #include<cstdlib>
      5 #include<cstdio>
      6 #include<set>
      7 #include<map>
      8 #include<vector>
      9 #include<cstring>
     10 #include<stack>
     11 #include<cmath>
     12 #include<queue>
     13 using namespace std;
     14 #define CL(x,v); memset(x,v,sizeof(x));
     15 #define INF 0x3f3f3f3f
     16 #define LL long long
     17 const int SIGMA_SIZE = 26;
     18 const int MAXNODE = 111000;
     19 const int MAXS = 150 + 10;
     20 
     21 struct ACautomata
     22 {
     23     int ch[MAXNODE][SIGMA_SIZE];
     24     int f[MAXNODE];    // fail函数
     25     int val[MAXNODE];  // 每个字符串的结尾结点都有一个非0的val
     26     int last[MAXNODE]; // 输出链表的下一个结点
     27     int next[MAXS];
     28     int sz;
     29     int count[1005][1005];
     30     void init()
     31     {
     32         sz = 1;
     33         memset(ch[0], 0, sizeof(ch[0]));
     34         memset(count,0,sizeof(count));
     35         memset(next,0,sizeof(next));
     36     }
     37 
     38     // 字符c的编号
     39     int idx(char c)
     40     {
     41         return c-'a';
     42     }
     43 
     44     // 插入字符串。v必须非0
     45     void insert(char *s, int v)
     46     {
     47         int u = 0, n = strlen(s);
     48         for(int i = 0; i < n; i++)
     49         {
     50             int c = idx(s[i]);
     51             if(!ch[u][c])
     52             {
     53                 memset(ch[sz], 0, sizeof(ch[sz]));
     54                 val[sz] = 0;
     55                 ch[u][c] = sz++;
     56             }
     57             u = ch[u][c];
     58         }
     59         if(val[u])
     60         {
     61             next[v]=val[u];
     62         }
     63         val[u] = v;
     64     }
     65 
     66     // 递归打印匹配文本串str[i]结尾的后缀,以结点j结尾的所有字符串
     67     void print(int i,int j,int x)
     68     {
     69         if(j)
     70         {
     71             if(x-val[j]+1>0)
     72                 count[x-val[j]+1][i]++;
     73             int t=val[j];
     74             while(next[t])
     75             {
     76                 t=next[t];
     77                 if(x-t+1>0)
     78                     count[x-t+1][i]++;
     79             }
     80             print(i,last[j],x);
     81         }
     82     }
     83 
     84     // 在T中找模板
     85     int find(char* T,int x)
     86     {
     87         int n = strlen(T);
     88         int j = 0; // 当前结点编号,初始为根结点
     89         for(int i = 0; i < n; i++)   // 文本串当前指针
     90         {
     91             int c = idx(T[i]);
     92             j = ch[j][c];
     93             if(val[j]) print(i,j,x);
     94             else if(last[j]) print(i,last[j],x); // 找到了!
     95         }
     96     }
     97 
     98     // 计算fail函数
     99     void getFail()
    100     {
    101         queue<int> q;
    102         f[0] = 0;
    103         // 初始化队列
    104         for(int c = 0; c < SIGMA_SIZE; c++)
    105         {
    106             int u = ch[0][c];
    107             if(u)
    108             {
    109                 f[u] = 0;
    110                 q.push(u);
    111                 last[u] = 0;
    112             }
    113         }
    114         // 按BFS顺序计算fail
    115         while(!q.empty())
    116         {
    117             int r = q.front();
    118             q.pop();
    119             for(int c = 0; c < SIGMA_SIZE; c++)
    120             {
    121                 int u = ch[r][c];
    122                 if(!u)
    123                 {
    124                     ch[r][c]=ch[f[r]][c];
    125                     continue;
    126                 }
    127                 q.push(u);
    128                 int v = f[r];
    129                 while(v && !ch[v][c]) v = f[v];
    130                 f[u] = ch[v][c];
    131                 last[u] = val[f[u]] ? f[u] : last[f[u]];
    132             }
    133         }
    134     }
    135 
    136 };
    137 ACautomata solver;
    138 char str[1005][1005];
    139 char str1[105][105];
    140 int main()
    141 {
    142     int T;
    143     scanf("%d",&T);
    144     while(T--)
    145     {
    146         int N,M,X,Y;
    147         scanf("%d%d",&N,&M);
    148         for(int i=1; i<=N; i++)
    149             scanf("%s",str[i]);
    150         scanf("%d%d",&X,&Y);
    151         for(int i=1; i<=X; i++)
    152             scanf("%s",str1[i]);
    153         solver.init();
    154         for(int i=1; i<=X; i++)
    155         {
    156             solver.insert(str1[i],i);
    157         }
    158         solver.getFail();
    159         for(int i=1; i<=N; i++)
    160         {
    161             solver.find(str[i],i);
    162         }
    163         int ans=0;
    164         for(int i=1; i<=N; i++)
    165             for(int j=1; j<=M; j++)
    166                 if(solver.count[i][j]==X)
    167                     ans++;
    168         printf("%d
    ",ans);
    169     }
    170     return 0;
    171 }
    View Code
  • 相关阅读:
    【leetcode】Triangle (#120)
    【leetcode】Unique Binary Search Trees (#96)
    【leetcode】Maximum Subarray (53)
    【转】算法杂货铺——k均值聚类(K-means)
    EM算法总结
    人工智能聚类算法总结
    K-MEANS算法总结
    在线制作css动画——CSS animate
    IOS 固定定位底部input输入框,获取焦点时弹出的输入法键盘挡住input
    响应式、手机端、自适应 百分比实现div等宽等高的方法
  • 原文地址:https://www.cnblogs.com/ITUPC/p/5024854.html
Copyright © 2011-2022 走看看