1194: [HNOI2006]潘多拉的盒子 - BZOJ

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

 

终于AC了

网上说的那个二元组的确很神奇,用bfs判断出两个咒语机的关系,初始状态为(0,0),状态(x,y)表示在A咒语机上x格停留,在B咒语机上y格停留

当有一个状态(x,y)x是输出元,而y不是的话,则B咒语机有一个咒语不能产生而A能产生

现在我们求出了一个有向图,要求最长链,首先就是要消去环,我们发现咒语机不可能出现A-->B-->C-->A但是A不是C的升级,相当于A>=B>=C>=A那么A,B,C相等

所以我们对点进行染色,对于一个没有染色的点,我们把和它等价的点涂成一样的颜色(也就是一个强连通分量),只要i到j有边,j到i有边,i和j就是一个强连通分量里的,否则就不是

染完色之后缩点,就是一个森林了,于是dp出最大权值链(这时点上有权,就是涂成这个颜色的点的个数)

主要是因为如果打tarjan太长了,根本不想打,而且只有50个点,明显就是给我们乱搞的嘛

 

  1 var
  2     p:array[0..50,0..50,0..1]of longint;
  3     flag,l:array[0..50,0..50]of boolean;
  4     n:longint;
  5  
  6 function max(x,y:longint):longint;
  7 begin
  8     if x>y then exit(x);
  9     exit(y);
 10 end;
 11  
 12 procedure init;
 13 var
 14     i,j,a,b,k:longint;
 15 begin
 16     read(n);
 17     for i:=1 to n do
 18       begin
 19         read(a,b);
 20         for j:=1 to b do
 21           begin
 22             read(k);
 23             flag[i,k]:=true;
 24           end;
 25         for j:=0 to a-1 do
 26           read(p[i,j,0],p[i,j,1]);
 27       end;
 28 end;
 29  
 30 var
 31     d:array[0..2500,0..1]of longint;
 32     v:array[0..50,0..50]of boolean;
 33  
 34 procedure work;
 35 var
 36     i,j,k,head,tail:longint;
 37     flagi,flagj:boolean;
 38 begin
 39     for i:=1 to n-1 do
 40       for j:=i+1 to n do
 41         begin
 42           head:=1;
 43           tail:=1;
 44           d[1,0]:=0;
 45           d[1,1]:=0;
 46           fillchar(v,sizeof(v),true);
 47           v[0,0]:=false;
 48           flagi:=true;
 49           flagj:=true;
 50           while head<=tail do
 51             begin
 52               if flag[i,d[head,0]]<>flag[j,d[head,1]] then
 53               begin
 54                 if flag[i,d[head,0]] then flagj:=false;
 55                 if flag[j,d[head,1]] then flagi:=false;
 56               end;
 57               if (flagi=false)and(flagj=false) then break;
 58               for k:=0 to 1 do
 59                 if v[p[i,d[head,0],k],p[j,d[head,1],k]] then
 60                 begin
 61                   v[p[i,d[head,0],k],p[j,d[head,1],k]]:=false;
 62                   inc(tail);
 63                   d[tail,0]:=p[i,d[head,0],k];
 64                   d[tail,1]:=p[j,d[head,1],k];
 65                 end;
 66               inc(head);
 67             end;
 68           if flagi then l[i,j]:=true;
 69           if flagj then l[j,i]:=true;
 70         end;
 71 end;
 72  
 73 var
 74     map:array[0..50,0..50]of boolean;
 75     c,f,du,s:array[0..50]of longint;
 76     vis:array[0..50]of boolean;
 77     col,num,ans:longint;
 78  
 79 procedure get;
 80 var
 81     i,j:longint;
 82 begin
 83     for i:=1 to n do
 84       if c[i]=0 then
 85       begin
 86         inc(col);
 87         c[i]:=col;
 88         inc(s[col]);
 89         for j:=1 to n do
 90           if l[i,j] and l[j,i] then
 91           begin
 92             c[j]:=col;
 93             inc(s[col]);
 94           end;
 95       end;
 96     for i:=1 to n do
 97       for j:=1 to n do
 98         if c[i]<>c[j] then
 99         if l[i,j] then map[c[i],c[j]]:=true;
100     for i:=1 to col do
101       for j:=1 to col do
102         if map[i,j] then inc(du[j]);
103     fillchar(vis,sizeof(vis),true);
104     num:=col;
105     while num>0 do
106       begin
107         for i:=1 to col do
108           if (vis[i])and(du[i]=0) then
109           begin
110             vis[i]:=false;
111             dec(num);
112             for j:=1 to col do
113               if map[i,j] then
114               begin
115                 dec(du[j]);
116                 f[j]:=max(f[j],f[i]+s[i]);
117               end;
118           end;
119       end;
120     for i:=1 to col do
121       ans:=max(ans,f[i]+s[i]);
122     write(ans);
123 end;
124  
125 begin
126     init;
127     work;
128     get;
129 end.
View Code

 

转载于:https://www.cnblogs.com/Randolph87/p/3590835.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值