潘多拉的盒子(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

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;
}
原文地址:https://www.cnblogs.com/harden/p/6392002.html