• BZOJ1194: [HNOI2006]潘多拉的盒子(tarjan)


    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

    解题思路:

    考虑升级关系的判定。
    枚举两个图。
    由于这个图的特殊性,那就是永远不会失配。
    那么我们就只需要判定输出位置就好了。
    由于具有高度循环性,只需要Bfs一遍判断就好了。
    最后判断包含关系,很显然图中具有传递性
    而传递回来只能说明图之间等价。
    那么就tarjan缩点跑个Dp就好了。
    代码:
      1 #include<queue>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 struct Pr_ma{
      6     struct pnt_{
      7         int ch[2];
      8         bool out;
      9     }p[100];
     10     int n,m;
     11     int can;
     12     int f;
     13     void Insert(void)
     14     {
     15         scanf("%d%d",&n,&m);
     16         for(int i=1;i<=m;i++)
     17         {
     18             int id;
     19             scanf("%d",&id);
     20             p[id].out=true;
     21         }
     22         for(int i=0;i<n;i++)
     23             scanf("%d%d",&p[i].ch[0],&p[i].ch[1]);
     24         return ;
     25     }
     26 }pr[51];
     27 struct pnt{
     28     int hd;
     29     int dfn;
     30     int low;
     31     int blg;
     32     bool vis;
     33     void res(int x)
     34     {
     35         dfn=low=x;
     36         return ;
     37     }
     38 }p[100];
     39 struct pnt_{
     40     int hd;
     41     int wgt;
     42     int ind;
     43 }p_[100];
     44 struct ent{
     45     int twd;
     46     int lst;
     47 }e[10000],e_[10000];
     48 struct int_{int x;int y;};
     49 int n;
     50 int cnt;
     51 int s_t;
     52 int c_t;
     53 int stt;
     54 int col;
     55 int cnt_;
     56 int dp[100000];
     57 int sta[100000];
     58 int_ stack_[100000];
     59 bool vis[100][100];
     60 std::queue<int>Q;
     61 std::queue<int_>Q_;
     62 void ade(int f,int t)
     63 {
     64     cnt++;
     65     e[cnt].twd=t;
     66     e[cnt].lst=p[f].hd;
     67     p[f].hd=cnt;
     68     return ;
     69 }
     70 void ade_(int f_,int t_)
     71 {
     72     cnt_++;
     73     e_[cnt_].twd=t_;
     74     e_[cnt_].lst=p_[f_].hd;
     75     p_[f_].hd=cnt_;
     76     p_[t_].ind++;
     77     return ;
     78 }
     79 bool Bfs(Pr_ma x_,Pr_ma y_)
     80 {
     81     while(!Q_.empty())Q_.pop();
     82     memset(vis,0,sizeof(vis));
     83     Q_.push(stack_[0]);
     84     while(!Q_.empty())
     85     {
     86         int_ h=Q_.front();Q_.pop();
     87         if(vis[h.x][h.y])continue;
     88         vis[h.x][h.y]=true;
     89         stack_[++s_t]=h;
     90         if(x_.p[h.x].out&&!y_.p[h.y].out)return false;
     91         int nx,ny;
     92         for(int c=0;c<2;c++)
     93         {
     94             nx=x_.p[h.x].ch[c];
     95             ny=y_.p[h.y].ch[c];
     96             Q_.push((int_){nx,ny});
     97         }
     98     }
     99     return true;
    100 }
    101 void tarjan(int x)
    102 {
    103     p[x].vis=true;
    104     sta[++stt]=x;
    105     p[x].res(++c_t);
    106     for(int i=p[x].hd;i;i=e[i].lst)
    107     {
    108         int to=e[i].twd;
    109         if(p[to].dfn&&!p[to].blg)
    110             p[x].low=std::min(p[x].low,p[to].dfn);
    111         else if(!p[to].dfn)
    112         {
    113             tarjan(to);
    114             p[x].low=std::min(p[x].low,p[to].low);
    115         }
    116     }
    117     if(p[x].dfn==p[x].low)
    118     {
    119         col++;
    120         int u;
    121         do{
    122             p_[col].wgt++;
    123             u=sta[stt--];
    124             p[u].blg=col;
    125         }while(u!=x);
    126     }
    127     return ;
    128 }
    129 int Top_sort(void)
    130 {
    131     while(!Q.empty())Q.pop();
    132     int ans=0;
    133     for(int i=1;i<=col;i++)if(!p_[i].ind)
    134         Q.push(i);
    135     while(!Q.empty())
    136     {
    137         int x=Q.front();Q.pop();
    138         dp[x]+=p_[x].wgt;
    139         for(int i=p_[x].hd;i;i=e_[i].lst)
    140         {
    141             int to=e_[i].twd;
    142             p_[to].ind--;
    143             dp[to]=std::max(dp[to],dp[x]);
    144             if(!p_[to].ind)Q.push(to);
    145         }
    146         ans=std::max(ans,dp[x]);
    147     }
    148     return ans;
    149 }
    150 int main()
    151 {
    152 //    freopen("pandora.in","r",stdin);
    153 //    freopen("pandora.out","w",stdout);
    154     scanf("%d",&n);
    155     for(int i=1;i<=n;i++)pr[i].Insert();
    156     for(int i=1,j;i<=n;i++)for(j=1;j<=n;j++)if(i!=j)
    157         if(Bfs(pr[i],pr[j]))ade(i,j);
    158     for(int i=1;i<=n;i++)if(!p[i].blg)
    159         tarjan(i);
    160 //    for(int i=1;i<=n;i++)printf("%d
    ",p[i].blg);
    161     for(int u=1;u<=n;u++)
    162     {
    163         for(int i=p[u].hd;i;i=e[i].lst)
    164         {
    165             int v=e[i].twd;
    166             int x=p[u].blg;
    167             int y=p[v].blg;
    168             if(x!=y)ade_(x,y);
    169         }
    170     }
    171     printf("%d
    ",Top_sort());
    172     return 0;
    173 }
  • 相关阅读:
    Android中TextView设置下划线
    BottomSheetDialogFragment 如何设置高度和禁止滑动(Kotlin)
    [iOS]使用GCD创建定时器
    [iOS]定时器NSTimer、CADisplayLink的内存管理
    [iOS]dispatch_after()中self和weakself的使用
    [Flutter]在Mac上安装Flutter运行环境
    wx小程序反编译为js代码
    Android | 玩转AppBarLayout,设置scrollFlags滑动属性详解
    玩转微信 | 炫酷的聊天满屏掉爱心系列,赶紧收藏
    Android使用更简单的方式实现滑块拼图验证码功能
  • 原文地址:https://www.cnblogs.com/blog-Dr-J/p/10306641.html
Copyright © 2020-2023  润新知