tarjan(縮點)
阿新 • • 發佈:2018-09-17
int span show 代碼 傳遞 喜歡 過程 pan 數據
剛做了兩道tarjan縮點的題,新學的算法總結一下。
推薦題:(難度單調遞增)
[HAOI2006]受歡迎的牛
[USACO5.3]校園網Network of Schools
間諜網絡
[APIO2009]搶掠計劃
這裏不教tarjan,要學的找別的博客吧。
總結:tarjan 簡單來說 算法過程 就是找環或單獨的點,這就可以構成強聯通分量。
代碼如下:
void tarjan(int u){ low[u]=dfn[u]=++cnt; stk[++top]=u; vis[u]=1; for(register int i=head[u];i;i=edge[i].next){int v=edge[i].to; if(!dfn[v]){ tarjan(v); low[u]=min(low[u],low[v]); } else if(vis[v]) low[u]=min(low[u],dfn[v]); } if(dfn[u]==low[u]){ co[u]=++col; vis[u]=0; while(stk[top]!=u){ vis[stk[top]]=0; co[stk[top]]=col; top--; } top--; } }
縮點也很簡單,根據col重新建個圖就行了。
tarjan縮點題的一些特征和突破口:
1.一般tarjan縮點的題會給你具有傳遞性的圖,利用傳遞性可以省略掉一些點,例如:如果a喜歡b,b喜歡c,那麽a就喜歡c。假設c又喜歡a,這就可以構成一個強連通分量,縮點即可,沒錯,這就是“受歡迎的牛”。
2.點的入度和出度是很重要的,很多題就圍繞這這個東西去變式,關註點的入度和出度,往往會找到突破口。
3.有的題需要記錄一些強連通分量內的數據
(1)可以在同一強連通分量中的點出棧的過程中更新,這樣比較方便簡單。
(2)也可以在主程序中再次for循環去更新,那樣就比較麻煩了,時間復雜度和空間復雜度都得增加,然而我第一次打這類題就是這麽操作的,代碼90行。
反思:還是理解不夠深,我的tarjan總是打錯一點,然後又去修改,還是得多模擬一下tarjan縮點的過程。
tarjan(縮點)