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个点,明显就是给我们乱搞的嘛
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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.