요약 학습 회문 트리 (회문 자동 기계)

"회문 나무"로 번역 상동 나무, 전문 처리 회문 문자열 데이터 Manachar 알고리즘과 유사한 구조,하지만 더 강력하다. 두 트리 포인터 실패 사이의 연결은 각각 홀수 트리는 각 노드는 문자 스트링의 팔린 드롬 서열을 나타내는 팔린 드롬 서열 두 팔린 드롬 서열 트리 저장 기억 짝수가된다. (바이두 백과 사전에서 발췌)

회문 나무는 쉽게 해결할 수 회문 문자열에 관련된 대부분의 문제, 예를 들어, 가장 긴 회문 문자열의 시작 부분에서 약간의 두 번째로 긴 회문 문자열 ..., 텍스트 문자열 회문에 걸쳐 발생 횟수, 누가 ... 매우 강력한 가장 긴 회문 문자열, 그리고 코드는 간단하다, 희귀 한 회문 문자열 이슈로 설명 할 수있다. 높은 효율 (nlogn)은 여기 회문 트리의 내 거친 이해의 일부입니다.

회문 나무 트라이을 필요로 알아,하지만 우리가 할 수 트라이 그것이 있어야한다, 세부 사항에 갈 ...

노드 번호가 0 인 것을 우리 상동 나무, 두 개의 루트 노드는 0과 1, 노드이다이 때문에 짝수의 길이와 홀수 길이 - 우리는 두 상동 문자열이 있다는 것을 알고있다. 짝수 팔린 드롬 문자열 루트 노드의 제 1 홀수 루트의 팔린 드롬 서열의 길이

그림 삽입 설명 여기
트리의 각 노드가 무엇을 나타내는 회문 방송 위의 그림은, 다음 제지도에서, 의미 어레이 -fail 회문 트리 코어 관계이다;

그림 삽입 설명 여기

(A 좋은 사진 왜곡 심각)

---- 보여주는 매우 선명하게 관찰 할 수있는 현재 노드에 FAI 포인터를 긴 회문 시퀀스 뷰의 끝 지점입니다
구성이 회문 후 코드 트리를 볼 수는 매우 간단된다 ...
코드에 :

#include <iostream>
#include <cstring>
#include <algorithm>
#define MAX 10010
using namespace std;

struct node {
    int len[MAX];//每个节点所对应字符串的长度
    int fail[MAX];//******核心中的核心
    int nxt[MAX][200];//字典树
    int p, tot,last;//p为回文树中总节点个数,tot为插入的总字符个数
    int s[MAX];//已经插入的字符串
    void init()//构建两个空节点
    {
        p = 0;
        tot = 0;
        last = 0;
        newnode(0);
        newnode(-1);//-1精髓了(作用1:保证了奇回文串的长度为奇,作用2:保证getfail不会死循环)
        fail[0] = 1;//神来之笔
        s[0] = -1;//-1的意思为确保没有一个字符与第0位相等
    }

    int newnode(int l)
    {
        len[p] = l;
        return p++;
    }

    void insert(char c)
    {
        s[++tot] = c;
        int cur =getfail(last);//cur为当前要回文树中插入的节点的父节点
        if (!nxt[cur][c])
        {
            int now = newnode(len[cur] + 2);//新建结点
            fail[now] = nxt[getfail(fail[cur])][c];//找到以该节点结尾的次长回文串
            nxt[cur][c] = now;
        }
        last = nxt[cur][c];
    }

    int getfail(int x)//整个算法的核心
    {
        while (s[tot - len[x] - 1] != s[tot]) x = fail[x];
        return x;
    }

}pt;

int main()
{
    pt.init();
    char a[MAX];
    cin.getline(a,MAX);
    for (int i = 0; i < strlen(a); i++)
    {
        pt.insert(a[i]);
    }
    int ans = 0;
    for (int i = 2; i < pt.p; i++)
    {
        ans = max(ans,pt.len[i]);
    }
    cout << ans;
    return 0;
}

그래서 강력한 알고리즘이 간단하므로 될 수 있을까?에 대한 놀라운이되지 않았습니다. % 거물급를.
반환되는 하위 문자열 사이의 연구에의 논리 트리가 바보 캐릭터의 경우라고 할 수있는 사실 회문 구조 ---- 리터 비트 문자열의 첫 번째 문자 (L-1)는 문자 (R + 1)에 대응하는 다음 비트, 일본어 캐릭터 (L-1)에 대응하는 (R + 1)에 대응하는 경우, 그 텍스트 문자열 일치 문자열이 서브 스트링은 팔린 드롬의 단부되는 회문이지만, 제 (L-1) 비트의 문자에 대응하는 (R + 1) 비트 문자 불일치를 대응한다면? 후 (R)의 열에서 두 번째 긴 회문을 찾을 당신이 된 경우 문자열은 다음 줄에 판단, 당신은 무엇을? 찾을 요구하는 경우는? 존재하지 않는, 위의 코드를주의 깊게 연구는 것을 발견 할 것이다 반복하는 X = 실패 [X]를 선택한 다음 최종 돌아올 것이다 (! 실패 [0] 공적) 노드 1 렌하면서 [1] = - 1; S [TOT - 렌 [X] - 1] 의 [TOT (미아오 아)와 동일해야한다.

위를 읽으면, 회문을 구축 할 것입니다 나무는, 우리는 많은 문제가 문자열을 회문 해결할 수 있습니다.
그러나 응용 프로그램은 여전히 회문 트리 나중에이 업데이 트를 종료하지 않는 것입니다.

게시 30 개 원래 기사 · 원의 찬양 9 · 전망 1306

추천

출처blog.csdn.net/Zhang_sir00/article/details/104182786