UVA11019 Matrix Matcher(一种计算子矩阵在母矩阵中出现次数的办法,AC自动机+kmp)


Problem H
Matrix Matcher
Input: 
Standard Input

Output: Standard Output

 

Given an N * M matrix, your task is to find the number of occurences of an X * Y pattern.

 

Input

The first line contains a single integer t(t ≤ 15), the number of test cases.

 

For each case, the first line contains two integers N and M (N, M ≤ 1000). The next N lines contain M characters each.

 

The next line contains two integers X and Y (X, Y ≤ 100). The next X lines contain Y characters each. 

 

Output

For each case, output a single integer in its own line, the number of occurrences.

Sample Input     Output for Sample Input

2 
1 1
x 
1 1
y 
3 3
abc 
bcd
cde 
2 2
bc
cd

                                                               0

                                                               2

 



Problem Setter: Rujia Liu, EPS

Special Thanks: Wenbin Tang

 

Warming: The judge input file size is about 7 MB. So please make sure that you use a fast IO function (eg. scanf()) to read input.


题目地址:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1960

 

说白了,判断一个子矩阵在母矩阵中出现的次数,怎么办?

矩阵中的元素是字母,字母是在'a'-'z'之间的

暴力扫不现实,用AC自动机来做。先把子矩阵的每一行当作一个模版串,构成AC自动机

然后把母矩阵的每一行当作文本串,放到自动机里去扫。

边扫边构成一个新的矩阵。新矩阵的定义是 i,j 这个位置在母矩阵中,如果是一个模版串的尾字母,那就存储这个尾字母对应的节点编号。否则存储0.

在之前构建自动机的时候,可以记录每一行它尾字母对应的节点的编号,这就构成一个新的模版串

而新的矩阵的每一列又可以看做一个新的文本串

这样,对新的模版串和m个新的文本串跑m发kmp.. 就可以求出子矩阵在母矩阵出现的次数了。


其实,AC自动机是必要的,再用上kmp是我自己想出来的。相信还有别的方法算出子矩阵在母矩阵中出现的次数。不管怎样,我就我的傻逼方法了

这题很好,算是一道综合题吧。I like it.


//Hello. I'm Peter.
#include<cstdio>
#include<iostream>
#include<sstream>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<cctype>
#include<ctime>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
typedef long double ld;
#define peter cout<<"i am peter"<<endl
#define input freopen("data.txt","r",stdin)
#define randin srand((unsigned int)time(NULL))
#define INT (0x3f3f3f3f)*2
#define LL (0x3f3f3f3f3f3f3f3f)*2
#define gsize(a) (int)a.size()
#define len(a) (int)strlen(a)
#define slen(s) (int)s.length()
#define pb(a) push_back(a)
#define clr(a) memset(a,0,sizeof(a))
#define clr_minus1(a) memset(a,-1,sizeof(a))
#define clr_INT(a) memset(a,INT,sizeof(a))
#define clr_true(a) memset(a,true,sizeof(a))
#define clr_false(a) memset(a,false,sizeof(a))
#define clr_queue(q) while(!q.empty()) q.pop()
#define clr_stack(s) while(!s.empty()) s.pop()
#define rep(i, a, b) for (int i = a; i < b; i++)
#define dep(i, a, b) for (int i = a; i > b; i--)
#define repin(i, a, b) for (int i = a; i <= b; i++)
#define depin(i, a, b) for (int i = a; i >= b; i--)
#define pi 3.1415926535898
#define eps 1e-6
#define MOD 1000000007
#define MAXN 1024
#define N 300100
#define M 26
char matrix[MAXN][MAXN];
char word[200];
int belong[200];
int n,m,x,y;
int num_node,trie[N][M],val[N];
int idx(char c){
    return c-'a';
}
void init_trie()
{
    clr(trie[0]);
    num_node=1;
}
void plant_trie(char *s,int len,int number)
{
    int now=0,letter;
    rep(i,0,len)
    {
        letter=idx(s[i]);
        if(!trie[now][letter])
        {
            trie[now][letter]=num_node;
            val[num_node]=0;
            clr(trie[num_node]);
            num_node+=1;
        }
        now=trie[now][letter];
    }
    val[now]=number;
    belong[number-1]=now;
}
int nextpos[N],lastpos[N];
queue<int>q;
void Build_nextlastpos()
{
    clr_queue(q);
    nextpos[0]=lastpos[0]=0;
    int now;
    rep(i,0,M)
    {
        now=trie[0][i];
        if(now)
        {
            nextpos[now]=0;
            lastpos[now]=0;
            q.push(now);
        }
    }
    int son,nextone;
    while(!q.empty())
    {
        now=q.front();
        q.pop();
        rep(i,0,M)
        {
            son=trie[now][i];
            nextone=nextpos[now];
            if(!son)
            {
                trie[now][i]=trie[nextone][i];//AC自动机优化
                continue;
            }
            while(nextone && !trie[nextone][i]) nextone=nextpos[nextone];//AC自动机优化
            nextpos[son]=trie[nextone][i];
            lastpos[son]=val[nextpos[son]]?nextpos[son]:lastpos[nextpos[son]];
            q.push(son);
        }
    }
}
int newmatrix[MAXN][MAXN];
void print(int row,int col,int pos)
{
    if(pos)
    {
        newmatrix[row-1][col-1]=pos;
        print(row,col,lastpos[pos]);
    }
}
void Aho_Corasick_search(int row,char *s,int len)
{
    int now=0,letter;
    repin(i,1,len)
    {
        letter=idx(s[i]);
        now=trie[now][letter];
        if(val[now]) print(row,i,now);
        else if(lastpos[now]) print(row,i,lastpos[now]);
    }
}
//上面是AC自动机
//下面是KMP
int kmpnext[MAXN];
void Build_kmpnext()
{
    int i,j;
    i=0;
    kmpnext[0]=j=-1;
    while(i<x)
    {
        if(j==-1 || belong[i]==belong[j])
        {
            kmpnext[i+1]=j+1;
            if(belong[j+1]==belong[i+1]) kmpnext[i+1]=kmpnext[j+1];//kmp优化
            i++;
            j=j+1;
        }
        else j=kmpnext[j];
    }
}
ll ans;
void kmp_search(int col)
{
    int i,j;
    i=j=0;
    while(i<n)
    {
        if(j==-1 || newmatrix[i][col]==belong[j])
        {
            i++;
            j++;
        }
        else j=kmpnext[j];
        if(j==x)
        {
            ans+=1;
            j=kmpnext[j];
        }
    }
}
int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        scanf("%d %d",&n,&m);
        repin(i,1,n)
        {
            repin(j,1,m)
            {
                newmatrix[i][j]=0;
            }
            scanf("%s",matrix[i]+1);
        }
        init_trie();
        scanf("%d %d",&x,&y);
        repin(i,1,x)
        {
            scanf("%s",word);
            plant_trie(word,y,i);
        }
        Build_nextlastpos();
        repin(i,1,n)
        {
            Aho_Corasick_search(i,matrix[i],m);
        }
        Build_kmpnext();
        ans=0;
        repin(j,1,m)
        {
            kmp_search(j);
        }
        printf("%lld\n",ans);
    }
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是使用 Python 和 OpenCV 计算图像匹配旋转矩阵和平移矩阵的示例代码: ``` import cv2 # 读取原始图像和目标图像 img1 = cv2.imread('image1.jpg', cv2.IMREAD_GRAYSCALE) img2 = cv2.imread('image2.jpg', cv2.IMREAD_GRAYSCALE) # 初始化 SIFT 特征提取器 sift = cv2.xfeatures2d.SIFT_create() # 提取原始图像和目标图像的 SIFT 特征点和特征描述 kp1, des1 = sift.detectAndCompute(img1, None) kp2, des2 = sift.detectAndCompute(img2, None) # 初始化匹配器 matcher = cv2.DescriptorMatcher_create(cv2.DescriptorMatcher_FLANNBASED) # 对两个图像的特征描述进行匹配 matches = matcher.match(des1, des2) # 选取最好的前 50 个匹配点 matches = sorted(matches, key=lambda x: x.distance)[:50] # 提取匹配点在原始图像和目标图像的坐标 src_pts = [kp1[m.queryIdx].pt for m in matches] dst_pts = [kp2[m.trainIdx].pt for m in matches] # 计算仿射变换矩阵 M = cv2.estimateAffine2D(src_pts, dst_pts)[0] # 输出旋转矩阵和平移矩阵 print('旋转矩阵:') print(M[:, :2]) print('平移矩阵:') print(M[:, 2]) # 在原始图像上画出匹配点和对应的线段 img3 = cv2.drawMatches(img1, kp1, img2, kp2, matches, None, flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS) cv2.imshow('matches', img3) cv2.waitKey() cv2.destroyAllWindows() ``` 在上面的示例代码,我们首先使用 SIFT 特征提取器提取原始图像和目标图像的特征点和特征描述,然后对它们进行匹配。接着,我们选取最好的前 50 个匹配点,并提取它们在原始图像和目标图像的坐标。最后,使用 `cv2.estimateAffine2D()` 函数计算出匹配点之间的仿射变换矩阵,即旋转矩阵和平移矩阵,并将其输出。同时,我们在原始图像上画出匹配点和对应的线段,以便观察匹配结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值