這篇隨筆講解圖論中lca問題(最近公共祖先)的幾種求解方式及實現方法。lca問題屬於高階圖論,所以希望讀者學習過初級圖論,知道圖的一些基本知識,並懂得深搜演算法的實現方式。這樣理解本篇部落格將會快捷、舒適。
理解lca問題,理解節點深度是至關重要的,大家可以畫一棵樹。在一棵樹中,所有的節點都有乙個深度。根節點的深度是1,其他節點的深度可以用深搜遍歷樹來處理出來。這樣,我們就可以通過深度陣列來實現解決lca問題的演算法。
樸素lca演算法的實現過程大約是這樣:對於詢問的兩個點\(x,y\),先判斷兩個點誰更深一些,然後把更深的點順著它的父節點一步步往上提公升,直到和\(y\)點的深度相等為止。然後同時提公升\(x,y\)兩點,直到這兩個點變成同乙個點,這時的那個點就是我們要求的lca。
根據這個演算法實現的特點,我們叫他「爬一爬」演算法。這種演算法極容易理解,但是奇慢無比。所以我們就不給**了。
剛剛提到的lca樸素演算法比較好理解,但是奇慢無比。所以我們推出了更高階一點的方法:倍增lca。倍增思想其實是非常好用的一種優化思想,在演算法優化中有很多使用例項。比如rmq問題的暴力方法用倍增優化之後就變成了st表(st演算法),比如lca的爬一爬演算法用倍增優化之後就變成了倍增lca演算法。
所謂倍增lca,其實很好理解,就是原來的樸素演算法是乙個乙個爬,我們現在變成一次爬\(2^k\)個,這樣就會大大優化複雜度。
實現的步驟並沒有任何變化:都是先爬比較小的那個,後一起爬。但是這個時候我們就要處理乙個二維陣列f。\(f[x][k]\)表示\(x\)的第\(2^k\)輩的祖先是誰。這樣,我們就可以得出乙個遞推式:
\[f[x][k]=f[f[x][k-1]][k-1]
\]需要說明的是,這裡需要提前處理出f陣列和deep陣列,對於這種操作,我們可以在樹上進行深搜來實現。
模板如下:
void dfs(int x,int f)
\)輩的祖先的第\(2^\)輩的祖先。
(其實這是個動態規劃的過程)
剩下的就是一些細節問題。請大家多多注意,以後求lca問題的時候根據不同的題目要求,就改這個模板即可。
**:int lca(int x,int y)
else
ret=fa[x][i];
} return ret;
}
割線法求解過程 幾種求解變力做功的方式
你好,我是方山。功的計算,在高中物理中經常涉及 功的計算公式 只適用於恒力做功的情況。而對於變力做功,則沒有乙個固定公式可用,但可以通過多種方法來求變力做功,如平均力法 圖象法 微元法 等效法,本篇文章就來詳細講解一下關於變力做功的方法。01 平均力 求解 在求解變力做功時,若物體受到的力方向不變,...
求解最短路問題的幾種方法總結
1 spfa求單源最短路,鏈式前向星存圖,時間複雜度o ke k是常數,大多數情況下為2。include include include using namespace std const int n int 1e5 11 最大點數 const int m int 1e6 11 最大邊數 const...
解決跨域問題的幾種方式
方式一 使用ajax的jsonp 方式二 使用cors外掛程式直接解決跨域問題,一般都是用 chrome瀏覽器的cors外掛程式 方式三 在web.xml中加上以下 cors com.thetransactioncompany.cors.corsfilter cors.alloworigin cor...