bzoj1194 [HNOI2006]潘多拉的盒子

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;
}

猜你喜欢

转载自blog.csdn.net/elijahqi/article/details/80059136