潘多拉的盒子(bzoj 1194)
Description
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
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
/* 思路比较简单:对于每对i,j,如果满足i能产生的所有字符串j都能产生,则建边,跑最长路。 但是图可能不是DAG,所以要先预处理缩点,然后再做。 */ #include<cstdio> #include<iostream> #include<cstring> #define N 60 using namespace std; int dfn[N],low[N],ins[N],sta[N],val[N],bl[N],indexx,num,top; int vis[N][N],head[N],head2[N],dp[N],S,cnt,a,b,flag; struct Node{int danger[N],lc[N],rc[N];};Node T[N]; struct node{int to,pre;};node e[N*N*2],e2[N*N*2]; void add(int u,int v){ e[++cnt].to=v; e[cnt].pre=head[u]; head[u]=cnt; } void add2(int u,int v){ e2[++cnt].to=v; e2[cnt].pre=head2[u]; head2[u]=cnt; } void dfs(int x,int y){ if(vis[x][y]||flag) return; vis[x][y]=1; if(T[b].danger[y]&&!T[a].danger[x]){flag=1;return;} dfs(T[a].lc[x],T[b].lc[y]); dfs(T[a].rc[x],T[b].rc[y]); } bool check(int i,int j){ flag=0;a=i;b=j; memset(vis,0,sizeof(vis)); dfs(1,1); if(!flag)return true; return false; } void tarjan(int x){ dfn[x]=low[x]=++indexx; sta[++top]=x; ins[x]=1; for(int i=head[x];i;i=e[i].pre){ int v=e[i].to; if(!dfn[v]){ tarjan(v); low[x]=min(low[x],dfn[v]); } else if(ins[v]) low[x]=min(low[x],low[v]); } int u; if(low[x]==dfn[x]){ ++num; do{ u=sta[top--]; val[num]++; bl[u]=num; ins[u]=0; }while(u!=x); } } int dfs2(int x){ if(dp[x])return dp[x]; int maxn=val[x]; for(int i=head2[x];i;i=e2[i].pre) maxn=max(maxn,dp[e2[i].to]+val[x]); dp[x]=maxn; return dp[x]; } int main(){ scanf("%d",&S); for(int s=1;s<=S;s++){ int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ int x;scanf("%d",&x); T[s].danger[x+1]=1; } for(int i=1;i<=n;i++){ int x,y;scanf("%d%d",&x,&y); T[s].lc[i]=x+1;T[s].rc[i]=y+1; } } for(int i=1;i<=S;i++) for(int j=1;j<=S;j++) if(i!=j&&check(i,j)) add(i,j); for(int i=1;i<=S;i++)if(!dfn[i])tarjan(i); for(int i=1;i<=S;i++) for(int j=head[i];j;j=e[j].pre) if(bl[i]!=bl[e[j].to])add2(bl[i],bl[e[j].to]); int ans=0; for(int i=1;i<=num;i++)ans=max(ans,dfs2(i)); printf("%d",ans); return 0; }