您的位置:首页 > 其它

Kattis taboo (AC自动机 拓扑排序 DP)

2016-11-17 20:18 726 查看

题目链接:点击这里

题意:给出n个01串,要构造一个最长的串使得这个串不包含所有出现过的串,无解输出-1.

首先把所有的点扔进自动机,因为出现过的串不能在我们构造的串中出现,所以事先把某些”坏点”标记,坏点指的就是每个串的结束节点以及沿着结束节点fail指针走下去的节点. 如果剩下的图中能够沿着根走出一个环那么必然就无解了, 判环可以用一遍拓扑确定. 排除无解情况剩下就是一个DAG了, 用dp[i][j]表示在自动机上i节点, 串长为j是否可行, 最后按照最长路打印方案即可.

#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
#include <cmath>
#include <algorithm>
#include <stack>
#define Clear(x,y) memset (x,y,sizeof(x))
#define fi first
#define se second
#define pii pair<int, int>
#define pli pair<long long, int>
#define pb push_back
#define mod 1000000007
template <class T>
inline bool scan (T &ret) {
char c;
int sgn;
if (c = getchar(), c == EOF) return 0; //EOF
while (c != '-' && (c < '0' || c > '9') ) c = getchar();
sgn = (c == '-') ? -1 : 1;
ret = (c == '-') ? 0 : (c - '0');
while (c = getchar(), c >= '0' && c <= '9') ret = ret * 10 + (c - '0');
ret *= sgn;
return 1;
}
using namespace std;
#define maxn 500005

int G[maxn][2];
void add_edge (int u, int v, int w) {
G[u][w] = v;
}

struct trie {
int next[maxn][2], fail[maxn];
long long end[maxn];
int root, cnt;
int new_node () {
memset (next[cnt], -1, sizeof next[cnt]);
end[cnt++] = 0;
return cnt-1;
}
void init () {
cnt = 0;
root = new_node ();
}
void insert (char *buf) {//字典树插入一个单词
int len = strlen (buf);
int now = root;
for (int i = 0; i < len; i++) {
int id = buf[i]-'0';
if (next[now][id] == -1) {
next[now][id] = new_node ();
}
now = next[now][id];
if (end[now]) break;
}
end[now]++;
}
void build () {//构建fail指针
queue <int> q;
fail[root] = root;
for (int i = 0; i < 2; i++) {
if (next[root][i] == -1) {
next[root][i] = root;
}
else {
fail[next[root][i]] = root;
q.push (next[root][i]);
}
}
while (!q.empty ()) {
int now = q.front (); q.pop ();
end[now] += end[fail[now]];
for (int i = 0; i < 2; i++) {
if (next[now][i] == -1) {
next[now][i] = next[fail[now]][i];
}
else {
fail[next[now][i]] = next[fail[now]][i];
q.push (next[now][i]);
}
}
}
}
int in[maxn], in2[maxn];
bool vis[maxn], inq[maxn];
void dfs1 (int u) {
for (int id = 0; id < 2; id++) {
int j = next[u][id];
if (end[j]) continue;
in[j]++;
in2[j]++;
if (in[j] == 1) dfs1 (j);
}
}
bool topo () {///判环
Clear (inq, 0);
Clear (vis, 0);
Clear (in, 0);
Clear (in2, 0);
int tot = 0, num = 0;
dfs1 (0);
queue <int> q; while (!q.empty ()) q.pop ();
if (in[0]) return 1;
inq[0] = 1, vis[0] = 1;
q.push (0); num++;
while (!q.empty ()) {
int u = q.front (); q.pop ();
for (int id = 0; id < 2; id++) {
int v = next[u][id]; if (end[v]) continue;
in[v]--;
vis[v] = 1;
if (!in[v]) {
q.push (v);
inq[v] = 1;
num++;
}
}
}
for (int i = 0; i < cnt; i++) {
if (inq[i] != vis[i]) {
return 1;
}
}
return 0;
}
int dp[maxn], to[maxn], Max;
int pre[maxn];

void dfs (int u) {
for (int id = 0; id < 2; id++) {
int v = next[u][id]; if (end[v]) continue;
dfs (v);
to[u] = max (to[u], to[v]+1);
if (to[v]+dp[u]+1 == Max) {
add_edge (u, v, id);
}
}
}
void query () {
if (topo ()) {
printf ("-1\n");
return ;
}
Clear (dp, 0);
queue <int> q; while (!q.empty ()) q.pop ();
q.push (0);
Max = 0;
while (!q.empty ()) {
int u = q.front (); q.pop ();
for (int id = 0; id < 2; id++) {
int j = next[u][id]; if (end[j]) continue;
if (dp[j] < dp[u]+1) {
dp[j] = dp[u]+1;
}
in2[j]--;
if (!in2[j]) {
q.push (j);
Max = max (Max, dp[j]);
}
}
}
Clear (G, -1);
Clear (to, 0);
dfs (0);
int u = 0;
while (dp[u] != Max) {
if (G[u][0] != -1) {
printf ("0");
u = G[u][0];
}
else {
printf ("1");
u = G[u][1];
}
}
printf ("\n");
}
}ac;

int n;
char buf[maxn];

int main () {
scanf ("%d", &n);
ac.init ();
for (int i = 0; i < n; i++) {
scanf ("%s", buf);
ac.insert (buf);
}
ac.build ();
ac.query ();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: