洛谷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
";
					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
";
	return 0;
}
原文地址:https://www.cnblogs.com/AlphaWA/p/10877713.html