洛谷2444(Trie图上dfs判环)

要点

  • 并没问具体方案,说明很可能不是构造。
  • 思考不断读入这个文本串,然后中间不出现某些文法的串。啊,这就是个自动机。
  • 将不合法串使用ac自动机构成一个Trie图,我们需要的字符串就是在这个自动机上无限走路但是却不会撞到危险节点。
  • 这样只要从根开始跑dfs判有环即存在答案。
  • 注意还要加上ac自动机的性质:某节点的fail指针指向的如果是危险的,则它也是危险的。"she"的'e'指向"he"的'e',说明she里有he,也是不可走。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <queue>
using namespace std;

const int maxn = 2005;
int n;
string s[maxn];

struct ac_auto {
    int ch[30005][2];
    int fail[30005];
    bool mark[30005];
    int vis[30005];
    int sz;

    void insert(string s) {
        int now = 0;
        for (int i = 0; i < s.length(); i++) {
            int c = s[i] - '0';
            if (!ch[now][c]) {
                ch[now][c] = ++sz;
                mark[sz] = 0;
            }
            now = ch[now][c];
        }
        mark[now] = 1;
    }

    void getfail() {
        queue<int> Q;
        for (int i = 0; i < 2; i++)
            if (ch[0][i])
                fail[ch[0][i]] = 0, Q.push(ch[0][i]);
        while (!Q.empty()) {
            int u = Q.front(); Q.pop();
            for (int i = 0; i < 2; i++)
                if (ch[u][i]) {
                    fail[ch[u][i]] = ch[fail[u]][i], Q.push(ch[u][i]);
                    if (mark[fail[ch[u][i]]])   mark[ch[u][i]] = 1;
                }
                else    ch[u][i] = ch[fail[u]][i];
        }
    }

    void dfs(int cur) {
        vis[cur] = 1;
        for (int i = 0; i < 2; i++) {
            int to = ch[cur][i];
            if (to) {
                if (mark[to])   continue;
                if (vis[to] == 1) {
                    cout << "TAK\n";
                    exit(0);
                }
                if (!vis[to])   dfs(to);
            }
        }
        vis[cur] = 2;
    }
}ac;

int main() {
    ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);

    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> s[i];
        ac.insert(s[i]);
    }
    ac.getfail();
    ac.dfs(0);
    cout << "NIE\n";
    return 0;
}

转载于:https://www.cnblogs.com/AlphaWA/p/10877713.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值