题目描述
有N个数A1..AN,已知一些它们之间的大小关系,形如某个数不小于某个数。
Your Task
把这N个数分成尽量少个集合,使得每个集合内的任意两个数的大小关系都是未知的。
输入文件
第一行 N M 表示有N个数,M个大小关系。
接下来M行,每行 i j 表示Ai>=Aj。
输出文件
一行包含一个整数,最少要分成多少个集合。
样例输入
4 4
1 2
1 3
1 4
4 1
样例输出
3
样例解释
2 3在同一个集合,1在一个集合,4在一个集合。
数据约定
20%:N<=18
60%:N<=10000
100%:N<=100000,M<=1000000
[题解]
很明显,题目中两个数间的大小关系是种偏序关系,这道题目也就是要求一个偏序集的最小反链覆盖.
由偏序集的相关知识我们可以知道,最小反链覆盖数等于最长链,所以这道题就是要求出一个有向图的最长链.
说到这里算法就出来了.由于有环的存在,对这道题,咱们先缩点,然后DFS一遍即可求出最长链(因为环上的点一定相等,所以都可以搞到最长链中).
考场上用的是YY的算法,复杂度铁定要跪.可怜我搞了这么久oi还不会tarjan= =.今天算是第一个tarjan,看起来还蛮简单的,特别是他一次退栈可以把一个强连通分量全搞出来,快也就是快在这里吧.由于是改的考场代码,所以奇丑无比= =.
Code
program main;
type int=longint;
var
i,j,k,m,n:int;
s,h,a,low,dfn,b,tail,dis,s_s:array[1..100000]of int;
ne,t:array[1..1000000]of int;
x,y,tot,high,ans:int;
function min(x,y:int):int;
begin
if x<y then exit(x) else exit(y);
end;
procedure dfs(x:int);var i:int;
begin
j:=h[x];b[x]:=10009;
inc(high);a[high]:=x;
dfn[x]:=high;
low[x]:=dfn[x];
while j<>0 do begin
i:=t[j];
if b[i]=0 then begin
dfs(i);
low[x]:=min(low[x],low[i]);
end else if(b[i]=10009)then begin
low[x]:=min(low[x],dfn[i]);
end;
j:=ne[j];
end;
if low[x]=dfn[x]then begin
for i:=dfn[x]to high do begin
s[a[i]]:=x;b[a[i]]:=8;a[i]:=0;
end;
high:=dfn[x]-1;
end;
end;
procedure deal(x:int);var i,j:int;
begin
b[x]:=18;
j:=h[x];
while j<>0 do begin
i:=t[j];
if b[i]<>18 then deal(i);
if dis[i]>dis[x]then dis[x]:=dis[i];
j:=ne[j];
end;
inc(dis[x],s_s[x]+1);
if dis[x]>ans then ans:=dis[x];
end;
begin
assign(input,'sort.in');reset(input);
assign(output,'sort.out');rewrite(output);
read(n,m);
for i:=1 to n do s[i]:=i;
for i:=1 to m do begin
read(x,y);inc(tot);
if h[x]=0 then tail[x]:=tot;
t[tot]:=y;ne[tot]:=h[x];h[x]:=tot;
end;
for i:=1 to n do if b[i]=0 then dfs(i);
for i:=1 to n do begin
if s[i]=i then continue;
ne[tail[s[i]]]:=h[i];h[i]:=0;tail[s[i]]:=tail[i];
inc(s_s[s[i]]);
end;
for i:=1 to m do t[i]:=s[t[i]];
ans:=0;
for i:=1 to n do if(b[i]<>18)and(s[i]=i)then deal(i);
write(ans);
close(input);close(output);
end.
写tarjan时犯了2个nc的错误:
(1)dfs时b数组在退栈前就清掉了
(2)缩点时没有改si的tail指针
附上另一个人的blog地址: http://blog.csdn.net/jerrydung/article/details/8039545他的代码是C++的.
BY QW
转载请注明出处