强奸久久久久久久|草草浮力在线影院|手机成人无码av|亚洲精品狼友视频|国产国模精品一区|久久成人中文字幕|超碰在线视屏免费|玖玖欧洲一区二区|欧美精品无码一区|日韩无遮一区二区

首頁 > 產(chǎn)品 > 經(jīng)驗(yàn) > tarjan,tarjan算法 為什么low

tarjan,tarjan算法 為什么low

來源:整理 時(shí)間:2023-09-03 00:32:01 編輯:智能門戶 手機(jī)版

本文目錄一覽

1,tarjan算法 為什么low

tarjan主要時(shí)間是用在RMQ的構(gòu)建上,即遍歷樹,然后構(gòu)造遍歷數(shù)組,構(gòu)造RMQ序列。 這里的時(shí)間復(fù)雜度大約是O(2*n*log(2*n))。 而對(duì)于一個(gè)詢問,處理速度大約是O(1),即從RMQ序列中查詢相應(yīng)節(jié)點(diǎn)的位置,以及對(duì)比操作。
沒看懂什么意思?

tarjan算法 為什么low

2,tarjan做LCA是不是很慢

不是,tarjan是正常人寫的算法中最快的。LCA可以經(jīng)過兩次轉(zhuǎn)化后做到O(n),但是這樣沒有太大實(shí)際意義,因?yàn)椴⒉榧膹?fù)雜度并不比這個(gè)大。
每深搜到一個(gè)節(jié)點(diǎn),都把與這個(gè)節(jié)點(diǎn)相關(guān)的查詢都處理掉了(包含有當(dāng)前節(jié)點(diǎn)的查詢),并不是所有的q個(gè)查詢所以總和是q而不是每個(gè)節(jié)點(diǎn)都是q
這個(gè)還慢嗎?可能是DFS調(diào)用棧的耗時(shí)比較多吧……

tarjan做LCA是不是很慢

3,最近公共祖先的算法

利用并查集優(yōu)越的時(shí)空復(fù)雜度,我們可以實(shí)現(xiàn)LCA問題的O(n+Q)算法,這里Q表示詢問的次數(shù)。Tarjan算法基于深度優(yōu)先搜索的框架,對(duì)于新搜索到 的一個(gè)結(jié)點(diǎn),首先創(chuàng)建由這個(gè)結(jié)點(diǎn)構(gòu)成的集合,再對(duì)當(dāng)前結(jié)點(diǎn)的每一個(gè)子樹進(jìn)行搜索,每搜索完一棵子樹,則可確定子樹內(nèi)的LCA詢問都已解決。其他的LCA詢 問的結(jié)果必然在這個(gè)子樹之外,這時(shí)把子樹所形成的集合與當(dāng)前結(jié)點(diǎn)的集合合并,并將當(dāng)前結(jié)點(diǎn)設(shè)為這個(gè)集合的祖先。之后繼續(xù)搜索下一棵子樹,直到當(dāng)前結(jié)點(diǎn)的所 有子樹搜索完。這時(shí)把當(dāng)前結(jié)點(diǎn)也設(shè)為已被檢查過的,同時(shí)可以處理有關(guān)當(dāng)前結(jié)點(diǎn)的LCA詢問,如果有一個(gè)從當(dāng)前結(jié)點(diǎn)到結(jié)點(diǎn)v的詢問,且v已被檢查過,則由于 進(jìn)行的是深度優(yōu)先搜索,當(dāng)前結(jié)點(diǎn)與v的最近公共祖先一定還沒有被檢查,而這個(gè)最近公共祖先的包涵v的子樹一定已經(jīng)搜索過了,那么這個(gè)最近公共祖先一定是v 所在集合的祖先。下面給出這個(gè)算法的偽代碼描述: LCA(u)d[i] 表示 i節(jié)點(diǎn)的深度, p[i,j] 表示 i 的 2^j 倍祖先那么就有一個(gè)遞推式子 p[i,j]=p[p[i,j-1],j-1]這樣子一個(gè)O(NlogN)的預(yù)處理求出每個(gè)節(jié)點(diǎn)的 2^k 的祖先然后對(duì)于每一個(gè)詢問的點(diǎn)對(duì)a, b的最近公共祖先就是:先判斷是否 d[a] > d[b] ,如果是的話就交換一下(保證 a 的深度小于 b 方便下面的操作)然后把b 調(diào)到與a 同深度, 同深度以后再把a(bǔ), b 同時(shí)往上調(diào)(dec(j)) 調(diào)到有一個(gè)最小的j 滿足p[a,j]!=p[b,j] (a b 是在不斷更新的), 最后再把 a, b 往上調(diào) (a=p[a,0], b=p[b,0]) 一個(gè)一個(gè)向上調(diào)直到a = b, 這時(shí) a or b 就是他們的最近公共祖先

最近公共祖先的算法

4,強(qiáng)連通分量的Tarjan算法思路

這個(gè)算法思路不難理解,由開篇第一句話可知,任何一個(gè)強(qiáng)連通分量,必定是對(duì)原圖的深度優(yōu)先搜索樹的子樹。那么其實(shí),我們只要確定每個(gè)強(qiáng)連通分量的子樹的根,然后根據(jù)這些根從樹的最低層開始,一個(gè)一個(gè)的拿出強(qiáng)連通分量即可。那么剩下的問題就只剩下如何確定強(qiáng)連通分量的根和如何從最低層開始拿出強(qiáng)連通分量了。那么如何確定強(qiáng)連通分量的根,在這里我們維護(hù)兩個(gè)數(shù)組,一個(gè)是indx[1..n],一個(gè)是mlik[1..n],其中indx[i]表示頂點(diǎn)i開始訪問時(shí)間,mlik[i]為與頂點(diǎn)i鄰接的頂點(diǎn)未刪除頂點(diǎn)j的mlik[j]和mlik[i]的最小值(mlik[i]初始化為indx[i])。這樣,在一次深搜的回溯過程中,如果發(fā)現(xiàn)mlik[i]==indx[i]那么,當(dāng)前頂點(diǎn)就是一個(gè)強(qiáng)連通分量的根,為什么呢?因?yàn)槿绻皇菑?qiáng)連通分量的根,那么它一定是屬于另一個(gè)強(qiáng)連通分量,而且它的根是當(dāng)前頂點(diǎn)的祖宗,那么存在包含當(dāng)前頂點(diǎn)的到其祖宗的回路,可知mlik[i]一定被更改為一個(gè)比indx[i]更小的值。至于如何拿出強(qiáng)連通分量,這個(gè)其實(shí)很簡單,如果當(dāng)前節(jié)點(diǎn)為一個(gè)強(qiáng)連通分量的根,那么它的強(qiáng)連通分量一定是以該根為根節(jié)點(diǎn)的(剩下節(jié)點(diǎn))子樹。在深度優(yōu)先遍歷的時(shí)候維護(hù)一個(gè)堆棧,每次訪問一個(gè)新節(jié)點(diǎn),就壓入堆棧?,F(xiàn) 在知道如何拿出了強(qiáng)連通分量了吧?是的,因?yàn)楫?dāng)前節(jié)點(diǎn)是這個(gè)強(qiáng)連通分量中最先被壓入堆棧的,那么在當(dāng)前節(jié)點(diǎn)以后壓入堆棧的并且仍在堆棧中的節(jié)點(diǎn)都屬于這個(gè)強(qiáng)連通分量。當(dāng)然有人會(huì)問真的嗎?假設(shè)一個(gè)節(jié)點(diǎn)在當(dāng)前節(jié)點(diǎn)壓入堆棧以后壓入并且還存在,同時(shí)它不屬于該強(qiáng)連通分量,那么它一定屬于另一個(gè)強(qiáng)連通分量,但當(dāng)前節(jié)點(diǎn)是它的根的祖宗,那么這個(gè)強(qiáng)連通分量應(yīng)該在此之前已經(jīng)被拿出?,F(xiàn) 在沒有疑問了吧,那么算法介紹就完了。

5,C Tarjan到底干嘛的怎么寫

Tarjan算法是用來求有向圖的強(qiáng)連通分量的。這是c++代碼,  #define M 50//題目中可能的最大點(diǎn)數(shù)  intSTACK[M],top=0;//Tarjan算法中的?! oolInStack[M];//檢查是否在棧中  intDFN[M];//深度優(yōu)先搜索訪問次序  intLow[M];//能追溯到的最早的次序  intComponentNumber=0;//有向圖強(qiáng)連通分量個(gè)數(shù)  intIndex=0;//索引號(hào)  vectorEdge[M];//鄰接表表示   vectorComponent[M];//獲得強(qiáng)連通分量結(jié)果   intInComponent[M];//記錄每個(gè)點(diǎn)在第幾號(hào)強(qiáng)連通分量里   intComponentDegree[M];//記錄每個(gè)強(qiáng)連通分量的度   voidTarjan(inti){intj;   DFN[i]=Low[i]=Index++;   InStack[i]=true;   STACK[++top]=i;   for(inte=0;e   {    j=Edge[i][e];    if(DFN[j]==-1)    {     Tarjan(j);    Low[i]=min(Low[i],Low[j]);    }    else if(InStack[j])     Low[i]=min(Low[i],Low[j]);   }   if(DFN[i]==Low[i])   {     ComponentNumber++;     do{     j=STACK[top--];     InStack[j]=false;     Component[ComponentNumber].push_back(j);     InComponent[j]=ComponentNumber;     }while(j!=i);   }
在c語言中return 表示從被調(diào)函數(shù)返回到主調(diào)函數(shù)繼續(xù)執(zhí)行,返回時(shí)可附帶一個(gè)返回值,由return后面的參數(shù)指定?! ∫虼耍赾語言中一般出現(xiàn)return語句,即改變程序執(zhí)行流程到母函數(shù)中,因此無論是在if語句還是while語句,還是其它的什么語句,return始終是返回母函數(shù)的調(diào)用,不需要細(xì)分什么情況。

6,求最近公共祖先的tarjan算法pascal標(biāo)程

首先從頂點(diǎn)a出發(fā),沿父指針將a至根的路徑上的所有頂點(diǎn)設(shè)訪問標(biāo)志。然后從b頂點(diǎn)出發(fā),沿父指針追溯到第1個(gè)已訪問的頂點(diǎn)b,該頂點(diǎn)即為a和b的最近公共祖先。var n,rt,a,b,i:integer;l,r,pt:array[0..max]of integer; vt:array[1..max]of boolean; readln(f,n,rt); for i:=1 to n do begin readln(l[i],r[i]); if i=rt then pt[rt]:=0 else pt[l[i]]:=i; pt[r[i]]:=i end; readln(a,b); while a*b<>0 do begin fillchar(vt,sizeof(vt),0); repeat vt[a]:=true;a:=pt[a] until a=0; while not vt[b] do b:=pt[b]; writeln(b);readln(a,b);End;
代碼可能比較長,不要介意。 思路:從根節(jié)點(diǎn)開始找,每次用深度優(yōu)先搜索的方法遍歷兒子節(jié)點(diǎn),如果遍歷到2個(gè)節(jié)點(diǎn)在該節(jié)點(diǎn)的兩個(gè)子樹集合里,則該點(diǎn)就是他們的lca。 具體方法:首先遍歷第一個(gè)子樹,如果遍歷到了其中一個(gè)節(jié)點(diǎn),另一個(gè)節(jié)點(diǎn)已經(jīng)遍歷到了,那么對(duì)改點(diǎn)做一次找祖先。每個(gè)子樹都這么做。如果沒有找到就將改點(diǎn)的父親節(jié)點(diǎn)變?yōu)樗母赣H。對(duì)每個(gè)子樹也是像這樣處理。 注意一個(gè)是另一個(gè)的祖先的情況。代碼如下:var father,son:array[0..10001] of longint;//father是返回時(shí)的父親節(jié)點(diǎn)編號(hào),原來指向自己,son是該節(jié)點(diǎn)的兒子個(gè)數(shù) s:array[0..10001,0..101] of longint;//表示一個(gè)節(jié)點(diǎn)的兒子編號(hào),因?yàn)閿?shù)據(jù)比較弱直接開數(shù)組,否則要用鏈表 f:array[0..10001] of boolean; i,j,t,n,get,u,v,x,y:longint;function find(x:longint):longint;begin if father[x]=x then exit(x) else father[x]:=find(father[x]); exit(father[x]);end;//并查集路徑壓縮,不解釋,網(wǎng)上題解比較多的procedure tarjan(x:longint);var i:longint;begin if f[u] and f[v] then exit; f[x]:=true; if (x=u) and f[v] then get:=find(v);//已經(jīng)找到了兩個(gè)節(jié)點(diǎn),顯然u的父親節(jié)點(diǎn)還沒有變動(dòng),但是v的已經(jīng)變動(dòng)過了,實(shí)質(zhì)上指向的是同一個(gè)祖先,所以找v的祖先。下面也是如此 if (x=v) and f[u] then get:=find(u); for i:=1 to son[x] do if not(f[s[x,i]]) then begin tarjan(s[x,i]);//遍歷子樹 father[s[x,i]]:=x;//沒有找到,父親節(jié)點(diǎn)指向它 end;end;begin readln(t); for i:=1 to t do begin readln(n); fillchar(f,sizeof(f),false); fillchar(son,sizeof(f),0); for j:=1 to n do father[j]:=j; for j:=1 to n-1 do begin readln(x,y); inc(son[x]); s[x,son[x]]:=y; father[y]:=x; end; readln(u,v); x:=find(n);//找樹根,不解釋 for j:=1 to n do father[j]:=j;//父親節(jié)點(diǎn)指向自己 tarjan(x); writeln(get); end;end.總結(jié):算法實(shí)質(zhì)是這樣的,首先找到了其中一個(gè)節(jié)點(diǎn),然后不斷向上,發(fā)現(xiàn)一個(gè)節(jié)點(diǎn)的另一個(gè)子樹中有另外一個(gè)節(jié)點(diǎn),那么這個(gè)節(jié)點(diǎn)就是他們的lca吐槽一句:你是因?yàn)榫W(wǎng)上的都是c++的然后就強(qiáng)調(diào)pascal的吧!好的話記得采納啊!純手打很累的!
文章TAG:算法為什么什么tarjan為什么low

最近更新

經(jīng)驗(yàn)文章排行榜