POJ 1204 Word Puzzles(AC自动机)

这题的数据卡在,如下:

5 5 3
ABCDE
FGHIJ
KLMNO
PQRST
UVWXY
PQR
RS
RST

puzzle中间的行中可以包含要查询的多个单词。这个问题很好解决,SearchDfa的时候别return就行了,一直搜到字符串的结尾。
但是这样做也有一个bug,如果数据是这样的:

4 7 5
ABCDEFG
HIJKLMN
OPQRSTU
VWXYZAK

RSTU
STU
TU 
JKL
KL

也就是说查询单词里面,大单词包含着小单词,实际上是很难处理的。我的一个设想是遇到所有危险节点的时候,都访问,该节点的所有前缀节点,并记录该前缀的位置信息,也就是要搜索的单词。这个搜索的时候同样不能return,因为小单词后面可能有大单词。
不过也可以搜索所有的点,每个点的8个方向都搜索一下,不过时间开销太大。
对于这题的输入其实很好处理,每一个单词都设置一个唯一的标号,然后构造tire的时候,在每个叶子节点上标记上这个唯一个标号。这样就是唯一的表示,不需要再这个单词的每一个字符上都标志它的标号,因为其他单词来的时候还得改,没用。

代码
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <vector>
#include <queue>
using namespace std;

const int maxn=1010;
const int LETTERS=26;
int nNodesCount=0;
int str_num=-1,l,c,w;;

struct CNode {
    CNode * pChilds[LETTERS];
    CNode * pPrev;
    bool bBadNode;
    int num;
    void Init() {
        memset(pChilds,0,sizeof(pChilds));
        pPrev=NULL;
        bool bBadNode=false;
    }
};

CNode Tree[maxn*maxn];
char puzzle[maxn][maxn];
char words[maxn][maxn];
int loc[maxn][3];
int d[8][2]={{-1,0},{1,0},{0,-1},{0,1},{-1,-1},{-1,1},{1,-1},{1,1}};
int pd[8]={0,4,6,2,7,1,5,3};
//上下左右 左上 右上 左下 右下 

void Insert(CNode * pRoot,char * s,int num)
{
    for (int i=0;s[i];i++) {
        if (pRoot->pChilds[s[i]-'A']==NULL) {
            pRoot->pChilds[s[i]-'A']=Tree+nNodesCount;
            nNodesCount++;
        }
        pRoot=pRoot->pChilds[s[i]-'A'];
    }
    pRoot->bBadNode=true;
    pRoot->num=num;
}

void BuildDfa()
{
    for (int i=0;i<LETTERS;i++) {
        Tree[0].pChilds[i]=Tree+1;
    }
    Tree[0].pPrev=NULL;
    Tree[1].pPrev=Tree;
    deque<CNode *> q;
    q.push_back(Tree+1);
    while (!q.empty()) {
        CNode * pRoot=q.front();
        q.pop_front();
        for (int i=0;i<LETTERS;i++) {
            CNode * p=pRoot->pChilds[i];
            if (p) {
                CNode * pPrev=pRoot->pPrev;
                while (pPrev) {
                    if (pPrev->pChilds[i]) {
                        p->pPrev=pPrev->pChilds[i];
                        if (p->pPrev->bBadNode) {
                            p->bBadNode=true;
                        }
                        break;
                    }
                    else {
                        pPrev=pPrev->pPrev;
                    }
                }
                q.push_back(p);
            }
        }
    }
}

void SearchDfa(int x,int y,int dir)
{
    CNode * p=Tree+1;
    while (x>=0&&x<l&&y>=0&&y<c) {
    	while (true) {
            if (p->pChilds[puzzle[x][y]-'A']) {
                p=p->pChilds[puzzle[x][y]-'A'];
                if (p->bBadNode) {
                	int len=strlen(words[p->num]);
                	loc[p->num][0]=x-(len-1)*d[dir][0];
                	loc[p->num][1]=y-(len-1)*d[dir][1];
                	loc[p->num][2]=pd[dir];
                }
                break;
            }
            else {
                p=p->pPrev;
            }
        }
        x+=d[dir][0];
        y+=d[dir][1];
	}
}

int main()
{
    nNodesCount=2;
    
    scanf("%d%d%d",&l,&c,&w);
    for (int i=0;i<l;i++) {
        scanf("%s",puzzle[i]);
    }
    for (int i=0;i<w;i++) {
        scanf("%s",words[i]);
        Insert(Tree+1,words[i],i);
    }
    BuildDfa();
	
	for (int i=0;i<l;i++) {
		for (int k=0;k<8;k++) {
			SearchDfa(i,0,k);
			SearchDfa(i,c-1,k);
		}
	}
	
	for (int j=0;j<c;j++) {
		for (int k=0;k<8;k++) {
			SearchDfa(0,j,k);
			SearchDfa(l-1,j,k);
		}
	}
	
    for (int i=0;i<w;i++) {
        printf("%d %d %c
",loc[i][0],loc[i][1],loc[i][2]+'A');
    }
    return 0;
}

/*
5 5 3
ABCDK
EFGHN
IJKLS
MNOPD
QRSTP


4 7 5
ABCDEFG
HIJKLMN
OPQRSTU
VWXYZAK

RSTU
STU
TU 
JKL
KL

*/

原文地址:https://www.cnblogs.com/xyqxyq/p/12328883.html