題目描述
有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
轉載請註明出處