​http://www.elijahqi.win/archives/3189​​​
Description

传说中,有个神奇的潘多拉宝盒。如果谁能打开,便可以拥有幸福、财富、爱情。可是直到真的打开,才发现与之
相随的还有灾难、不幸。其实,在潘多拉制造这个宝盒的时候,设置了一些咒语来封锁住灾难与不幸。然而,直到
科技高度发达的今天,人们才有希望弄懂这些咒语。所以说,上千年来,人们只得忍受着各种各样的疾病和死亡的
痛苦。然而,人类的命运从此改变了。经过数十年的研究,NOI组织在最近终于弄清楚了潘多拉咒语的原理。咒语
是由一个叫做咒语机的机器产生的。用现在的名词来解释,咒语机其实就是一个二进制产生器,它产生的一个二进
制字符串(这个字符串叫做咒语源)经加密后就形成了咒语。二进制产生器的结构是这样的:它由n个元件组成,
不妨设这n个元件的标号为0到n-1。在每个时刻,都有且仅有一个信号,它停留在某个元件上。一个信号就是一个
二进制字符串。最开始,有一个空串信号停留在元件0上。在某个时刻,如果有一个信号s停留在元件I上,那么,
这时元件i可以将信号后面加一个0,然后把信号传给元件pi,0,也可以将信号后面加一个1,然后传给元件pi,1。也
就是说,下一个时刻有可能,一种可能是一个信号S0(表示字串S后面加一个0形成的字串)仪在元件pi,0上,另一
种可能是有一个信号S1停留在元件pi,1上。有的元件可以将停留在它上面的信号输出,而输出的信号就成为了咒语
源,这样的元件叫做咒语源输出元。不难发现,有些口语源是可能由一个咒语机产生的,而另一些咒语源则不行。
例如,下图的咒语机能产生1,11,111,1111,…等咒语源,但是不能产生0,10,101等咒语源。在这个盒子上,有K个
咒语机,不妨将这些咒语机从0到K-1标号。可能有这种情况,一个咒语机i能够产生的口语源,咒语机j都能产生。
这时,我们称咒语机j是咒语机i的升级。而衡量这个例子的复杂程度的一种办法是:看这个盒子上升级次数最多的
一个咒语机。即:找到一个最长的升级序列a1,a2…at。该升级序列满足:序列中任意两个咒语机的标号都不同,
且都是0到k-1(包含0和k-1)之间的整数,且咒语机a2是咒语机a1的升级,咒语机a3是咒语机a2的升级…,咒语
机at是咒语机at-1的升级。你想远离灾难与不幸吗?你想从今以后沐浴幸福的阳光吗?请打开你的潘多拉之盒吧。
不过在拱形它之前,你先得计算一下宝盒上最长的升级序列。

Input

第一行是一个正整数S,表示宝盒上咒语机的个数,(1≤S≤50)。
文件以下分为S块,每一块描述一个咒语机,按照咒语机0,咒语机1…咒语机S-1的顺序描述。
每一块的格式如下。
一块的第一行有两个正整数n,m。分别表示该咒语机中元件的个数、咒语源输出元的个数
(1≤m≤n≤50)。
接下来一行有m个数,表示m个咒语源输出元的标号(都在0到n-1之间)。
接下来有n行,每一行两个数。第i行(0≤i≤n-1)的两个数表示pi,0和pi,1
(当然,都在0到n-1之间)。
Output

第一行有一个正整数t,表示最长升级序列的长度。

Sample Input

4
1 1
0
0 0
2 1
0
1 1
0 0
3 1
0
1 1
2 2
0 0
4 1
0
1 1
2 2
3 3
0 0
Sample Output

3
HINT

Source

题意:判断一个自动机所能输出的串是否另一个全部都能输出如果是 那么就认为被包含于另一个串 怎么做 暴力是指数级的 那就宽搜 因为宽搜的状态是n^2级别的所以 复杂度n^2
设{x,y}这个二元组表示当前处在a自动机的x位置 b自动机的y位置 判断如果x是出口y不是就直接退出即可
否则当把所有状态都搜索完认为是包含即可
然后暴力枚举每个的配对情况 每个都暴力bfs验证如果包含就建边 因为存在环所以先tarjan然后再拓扑dp求最长链即可

#include<queue>
#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
using namespace std;
inline char gc(){
static char now[1<<16],*S,*T;
if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if(T==S) return EOF;}
return *S++;
}
inline int read(){
int x=0,f=1;char ch=gc();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=gc();}
while(isdigit(ch)) x=x*10+ch-'0',ch=gc();
return x*f;
}
const int M=55;
struct Auto_M{
int n,m,trans[M][2],end[M];
}am[M];
struct node{
int y,next;
}data[M*M],data1[M*M];
struct node1{int x,y;};bool stackf[M];
int h1[M],h[M],b[M],s,T,in[M],num,dfn[M],low[M],q[M],top,size[M],dp[M];
inline bool bfs(const Auto_M &a,const Auto_M &b){
static node1 q[100000];static int l,r;l=1;r=0;
static bool visit[M][M];memset(visit,0,sizeof(visit));
q[++r]=(node1){0,0};visit[0][0]=1;
while(l<=r){static int x,y,xx,yy;
node1 lt=q[l++];x=lt.x;y=lt.y;
if(a.end[x]&&!b.end[y]) return 0;
for (int i=0;i<2;++i){
xx=a.trans[x][i],yy=b.trans[y][i];
if(visit[xx][yy]) continue;
visit[xx][yy]=1;q[++r]=(node1){xx,yy};
}
}return 1;
}
inline void insert1(int x,int y){
data[++num].y=y;data[num].next=h[x];h[x]=num;
}
inline void insert2(int x,int y){
data1[++num].y=y;data1[num].next=h1[x];h1[x]=num;
}
inline void tarjan(int x){
low[x]=dfn[x]=++num;stackf[x]=1;q[++top]=x;
for (int i=h[x];i;i=data[i].next){
int y=data[i].y;
if(!dfn[y]) tarjan(y),low[x]=min(low[x],low[y]);else if (stackf[y]) low[x]=min(low[x],dfn[y]);
}
if (dfn[x]==low[x]){
++s;int y;
do{y=q[top--];b[y]=s;++size[s];stackf[y]=0;
}while(x!=y);
}
}
int main(){
freopen("bzoj1194.in","r",stdin);
T=read();
for (int i=1;i<=T;++i){
am[i].n=read();am[i].m=read();
for (int j=1;j<=am[i].m;++j) am[i].end[read()]=1;
for (int j=0;j<am[i].n;++j) am[i].trans[j][0]=read(),am[i].trans[j][1]=read();
}
for (int i=1;i<=T;++i){
for (int j=1;j<=T;++j){
if (i==j) continue;
if(bfs(am[i],am[j])) insert1(i,j);//printf("%d %d\n",i,j);
}
}num=0;queue<int>q;
for (int i=1;i<=T;++i) if (!dfn[i]) tarjan(i);num=0;
for (int x=1;x<=T;++x){
for (int i=h[x];i;i=data[i].next){
int y=data[i].y;if (b[x]==b[y]) continue;
++in[b[y]];insert2(b[x],b[y]);
}
}for (int i=1;i<=s;++i) if (!in[i]) q.push(i),dp[i]=size[i];
while(!q.empty()){
int x=q.front();q.pop();
for (int i=h1[x];i;i=data1[i].next){
int y=data1[i].y;if (!--in[y]) q.push(y);
dp[y]=max(dp[y],dp[x]+size[y]);
}
}int ans=0;
for (int i=1;i<=s;++i) ans=max(ans,dp[i]);
printf("%d\n",ans);
return 0;
}