题意:给定大写字母的前n个字符,然后给m个禁止的串,求一个最长的串不包含这些禁止的串(只包含大写字母前n个字符,禁止的串也是)。如无解输出“No”。
分析:无解的情况除了长度为0还有长度为正无穷。首先将禁止的串建ac机,把所有的禁止走的节点标记出来,然后在ac上判断是否存在环路,把ac看成一张有向图的话,相当于判断图是否为有向无环图。直接dfs判断是否有环:当当前节点还在遍历其子树的时候,子树的子树又回到该节点,那么就有环了,时间复杂度为O(n)n为节点数。找最长合法串:dp[cur]表示到达cur状态的最优解长度,road[cur]表示cur的选的字符。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <set>
#include <string>
using namespace std;
const int maxn = 50008;
int kd;
char s[maxn<<7];
struct trie
{
int son[maxn][26],fbd[maxn],fail[maxn];
int cnt,root;
int color[maxn],IsRing,road[maxn],dp[maxn];
int newnode()
{
fill(son[cnt],son[cnt]+kd,-1);
fbd[cnt]=0;
return cnt++;
}
void Init()
{
cnt=0;
root=newnode();
}
void Insert(char str[])
{
int index,now=root,i;
for(i=0;str[i];i++)
{
index=str[i]-'A';
if(son[now][index]==-1)
son[now][index]=newnode();
now=son[now][index];
}
fbd[now]=1;
}
void findfail()
{
queue <int > q;
fail[root]=root;
int i,temp;
for(i=0;i<kd;i++)
if(son[root][i]==-1)
son[root][i]=root;
else
{
fail[son[root][i]]=root;
q.push(son[root][i]);
}
while(!q.empty())
{
temp=q.front();
q.pop();
fbd[temp]|=fbd[fail[temp]];
for(i=0;i<kd;i++)
if(son[temp][i]==-1)
son[temp][i]=son[fail[temp]][i];
else
{
fail[son[temp][i]]=son[fail[temp]][i];
q.push(son[temp][i]);
}
}
}
void dfs(int cur)
{
if(IsRing)
return ;
color[cur]=-1;
for(int i=0;i<kd;i++) if(!fbd[son[cur][i]])
{
if(color[son[cur][i]]==-1)
{
IsRing = 1;
return ;
}
else if(color[son[cur][i]]==0)
dfs(son[cur][i]);
}
color[cur]=1;
}
bool RingRd()
{
IsRing = 0;
memset(color,0,sizeof(color));
dfs(root);
return IsRing;
}
int DFS(int cur)
{
if(dp[cur]!=-1)
return dp[cur];
dp[cur]=0;
for(int i=kd-1;i>=0;i--) if(!fbd[son[cur][i]])
{
int temp=DFS(son[cur][i]);
if(temp+1>dp[cur])
{
dp[cur]=temp+1;
road[cur]=i;
}
}
return dp[cur];
}
void solve()
{
memset(dp,-1,sizeof(dp));
if(RingRd() || !DFS(root) )
{
printf("No\n");
return ;
}
int now=root;
for(int i=0;i<dp[root];i++)
{
putchar('A'+road[now]);
now=son[now][road[now]];
}
putchar('\n');
}
}ac;
int main()
{
int ncase,n;
scanf("%d",&ncase);
while(ncase--)
{
scanf("%d%d",&kd,&n);
ac.Init();
while(n--)
{
scanf("%s",s);
ac.Insert(s);
}
ac.findfail();
ac.solve();
}
return 0;
}