[BZOJ2938][POI2000]病毒(AC自动机+dfs)

题目

传送门

题解

这是一道比较锻炼思维的题,让我更加深的理解失配指针的作用
一般的AC自动机都是尽量多的匹配,这道题希望无限长,也就是希望能失配就失配,我们构造出trie树之后,在trie图(注意现在变成了一个图)上找环即可;
几点优化:根据trie树的性质.如果某个点的后缀是病毒,那么这个点肯定不能选
在dfs中,建立两个bool数组,一个需要回溯——用于在这条路径上找环,另一个不需要回溯——之前搜索过就不需要再搜索了

代码

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <queue>
#include <string>
using namespace std;
#define ll long long
const int maxn=2e6;
const int inf=1e9;

void debug(int *A,int len) {
   
   for (int i=1; i<=len; i++) printf("%d ",A[i]); printf("\n");}
int n,m;
string s;
struct Tree{
    int fail;
    int vis[30];
    int end;
}AC[maxn];

int cnt=0;
void build_AC(string s)
{
    int l=s.length(); int now=0;
    for (int i=0; i<l; i++)
    {
        if (!AC[now].vis[s[i]-'0'])
            AC[now].vis[s[i]-'0']=++cnt;
        now=AC[now].vis[s[i]-'0'];
    }
    AC[now].end++;
}

queue <int> q;
void Get_fail()
{
    for (int i=0; i<=1; i++)
        if (AC[0].vis[i]) q.push(AC[0].vis[i]);
    while (!q.empty())
    {
        int now=q.front(); q.pop();
        for (int i=0; i<=1; i++)
        {
            if (AC[now].vis[i])
            {
                AC[AC[now].vis[i]].fail=AC[AC[now].fail].vis[i];
                if (AC[ AC[ AC[now].vis[i] ].fail ].end) AC[AC[now].vis[i]].end++;//根据Tire树的性质优化 
                q.push(AC[now].vis[i]);
            }
            else AC[now].vis[i]=AC[AC[now].fail].vis[i];
        }
    }
}

bool vis[maxn],used[maxn];
bool dfs(int x)
{
    vis[x]=true;
    for (int i=0; i<=1; i++)
    {
        int to=AC[x].vis[i];
        if (vis[to]) return true;
        if (used[to] || AC[to].end) continue;//之前搜索过或有病毒,不必再搜索 
        if (dfs(to)) return true;
    }
    vis[x]=false;
    return false;
}

int main()
{
    scanf("%d",&n);
    for (int i=1; i<=n; i++)
    {
        cin>>s;
        build_AC(s);
    }
    Get_fail();

    if (dfs(0)) printf("TAK");
    else printf("NIE");
    return 0;
}

总结

1、转化的思想
2、dfs中两个bool数组,其实找环用topsort也可以
3、加快做题速度

猜你喜欢

转载自blog.csdn.net/A_Comme_Amour/article/details/80039917