POJ 1204 AC自动机

点击打开链接

题意:给个L*C的字符串矩阵,W个询问,对每个询问输出这个串第一次出现的位置及方向,共有8个方向,用A~H表示

思路:用AC自动机进行快速匹配,细节处理特别多,不看题解的话应该会WA很多次,还有一个处理的非常巧妙地地方,就是我们要输出第一次出现的位置,而AC自动机不能回溯,所以将串反着构造进字典树里,真是神犇,然后方向设置时也反着就可以了

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int maxn=500010;
const int N=26;
struct node{
    node *fail;
    node *next[N];
    int num;
    node(){
        fail=NULL;
        num=0;
        memset(next,NULL,sizeof(next));
    }
}*q[maxn];
node *root;
void insert_Trie(char *str,node *root,int id){
    node *p=root;
    int i=strlen(str)-1;
    while(i>=0){
        int id=str[i]-'A';
        if(p->next[id]==NULL) p->next[id]=new node();
        p=p->next[id];i--;
    }
    p->num=id;
}
void build_ac(node *root){
    root->fail=NULL;
    int head=0,tail=0;
    q[head++]=root;
    while(head!=tail){
        node *temp=q[tail++];
        node *p=NULL;
        for(int i=0;i<N;i++){
            if(temp->next[i]!=NULL){
                if(temp==root) temp->next[i]->fail=root;
                else{
                    p=temp->fail;
                    while(p!=NULL){
                        if(p->next[i]!=NULL){
                            temp->next[i]->fail=p->next[i];
                            break;
                        }
                        p=p->fail;
                    }
                    if(p==NULL) temp->next[i]->fail=root;
                }
                q[head++]=temp->next[i];
            }
        }
    }
}
//上,右上,右,右下,下,左下,左,左上;
int dir[8][2]={{-1,0},{-1,1},{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1}};
int ans[1010][10];
int L,C,W;
char str[1010][1010];
char str1[10010];
void query(int x,int y,int pos,int id){
    node *p=root,*temp;
    while(x>=0&&y>=0&&x<L&&y<C){
        int idid=str[x][y]-'A';
        while(p->next[idid]==NULL&&p!=root) p=p->fail;
        p=p->next[idid];
        p=(p==NULL)?root:p;
        temp=p;
        while(temp!=root){
            if(temp->num){
                int ttt=temp->num;
                if(ans[ttt][0]>x||(ans[ttt][0]==x&&ans[ttt][1]>y)){
                    ans[ttt][0]=x;ans[ttt][1]=y;ans[ttt][2]=id;
                }
            }
            temp=temp->fail;
        }
        x=x+dir[pos][0];
        y=y+dir[pos][1];
    }
}
void del(node *p){
     if(p==NULL)return ;
     for(int i=0;i<26;i++)del(p->next[i]);
     delete p;
}
int main(){
    while(scanf("%d%d%d",&L,&C,&W)!=-1){
        root=new node();
        for(int i=0;i<L;i++) scanf("%s",str[i]);
        for(int i=1;i<=W;i++){
            scanf("%s",str1);
            insert_Trie(str1,root,i);
            ans[i][0]=ans[i][1]=inf;
        }
        build_ac(root);
        for(int i=0;i<L;i++){
            query(i,0,2,6);query(i,C-1,6,2);
            query(i,0,1,5);query(i,C-1,5,1);
            query(i,0,3,7);query(i,C-1,7,3);
        }
        for(int i=0;i<C;i++){
            query(0,i,4,0);query(L-1,i,0,4);
            query(0,i,5,1);query(L-1,i,1,5);
            query(0,i,3,7);query(L-1,i,7,3);
        }
        for(int i=1;i<=W;i++){
            char ch=ans[i][2]+'A';
            printf("%d %d %c\n",ans[i][0],ans[i][1],ch);
        }
        del(root);
    }
    return 0;
}
时间: 2024-10-16 10:45:30

POJ 1204 AC自动机的相关文章

POJ 4052 AC自动机

[题意]: 给你n个字符串和一个文本,问有多少个字符串满足如下条件:该字符串包含在文本,该字符串不为其它字符串的子串. [知识点]: Ac自动机,处理字符串 [题解]: 集训比赛的时候当时被题目的数据量吓到了,不敢用ac自动机.但在网上看到题解时,然后瞬间就感觉自己想多了... 很水的一道ac自动机处理字符串的题目,先将查询的字符做成字典树,然后在文本中查找字符串是否存在. 在处理去子串上,我的做法是查找文本时去除后缀相同的包含子串.然后单独在搜索剩余可用字符串前缀相同子串. [代码]: 1 #

poj 2778 AC自动机 + 矩阵快速幂

// poj 2778 AC自动机 + 矩阵快速幂 // // 题目链接: // // http://poj.org/problem?id=2778 // // 解题思路: // // 建立AC自动机,确定状态之间的关系,构造出,走一步 // 能到达的状态矩阵,然后进行n次乘法,就可以得到状态间 // 走n步的方法数. // 精髓: // 1):这个ac自动机有一些特别,根节点是为空串,然而 // 每走一步的时候,如果没法走了,这时候,不一定是回到根 // 节点,因为有可能单个的字符时病毒,这样

poj 2778 AC自动机与矩阵连乘

http://poj.org/problem?id=2778 Description It's well known that DNA Sequence is a sequence only contains A, C, T and G, and it's very useful to analyze a segment of DNA Sequence,For example, if a animal's DNA sequence contains segment ATC then it may

POJ 2778 AC自动机+矩阵幂 不错的题

http://poj.org/problem?id=2778 有空再重新做下,对状态图的理解很重要 题解: http://blog.csdn.net/morgan_xww/article/details/7834801 另外做了矩阵幂的模板: //ac.sz是矩阵的大小 void mulmtr(long long x[MAXNODE][MAXNODE],long long y[MAXNODE][MAXNODE])//y=x*y { ll tmp[MAXNODE][MAXNODE]; for(in

POJ 3691 (AC自动机+状态压缩DP)

题目链接:  http://poj.org/problem?id=3691 题目大意:给定N的致病DNA片段以及一个最终DNA片段.问最终DNA片段最少修改多少个字符,使得不包含任一致病DNA. 解题思路: 首先说一下AC自动机在本题中的作用. ①字典树部分:负责判断当前0~i个字符组成的串是否包含致病DNA,这部分靠字典树上的cnt标记完成. ②匹配部分:主要依赖于匹配和失配转移关系的计算,这部分非常重要,用来构建不同字符间状态压缩的转移关系(代替反人类的位运算). 这也是必须使用AC自动机而

POJ 2896 AC自动机 or 暴力

DESCRIPTION :大意是说.给你n个代表病毒的字符串.m个表示网站的字符串.让你计算有多少个网站被病毒感染了.被那些病毒感染了. 刚开始就想暴力.然而,忽略了条件:每个网站最多有三个病毒.于是.TLE了.于是换AC 自动机.于是MLE了.于是把最大的结构体指针数组换成队列.用时间来换空间.23333 应该注意结构体的初始化是必须的. 附代码:AC 自动机: #include<stdio.h> #include<string.h> #include<iostream&g

poj 2778 AC自动机构建有向图 + 邻接矩阵快速幂

Problem: 给你m个病毒串,求指定长度n且不含病毒串作为子串的字符串一共有多少种. Analyse: 用AC自动机构建L个状态节点,每个节点的end标记记录是否在这里形成病毒串. 这里有个核心就是,如果当前后缀的子后缀(也就是它的fail指针指向的地方)是病毒串的话, 那么它就是病毒串. 然后根据这个AC自动机的L个节点来建立有向图的邻接矩阵B,B[i][j]代表从i到j状态的路径数量. B[0][j]代表的是从初始状态,还没有任何字符的时候转移到j状态,因为根节点0就是没有任何限制. 然

DNA Sequence POJ - 2778 AC 自动机 矩阵乘法

定义重载运算的时候一定要将矩阵初始化,因为这个调了一上午...... Code: #include<cstdio> #include<algorithm> #include<cstring> #include<queue> #include<string> #define maxn 100000 typedef long long ll; using namespace std; void setIO(string a){ freopen((a+

POJ 1204 Word Puzzles (AC自动机)

Word Puzzles Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 9926   Accepted: 3711   Special Judge Description Word puzzles are usually simple and very entertaining for all ages. They are so entertaining that Pizza-Hut company started us