1. 程式人生 > >lca倍增演算法學習記錄

lca倍增演算法學習記錄

找最近公共父節點這問題很容易想到讓兩節點一起往上走最後相遇,但這樣的dfs顯然很慢,於是就需要倍增。就是用二進位制的思維,以1,2,4,8等2的階層步長接近答案,比一步一步向上要快很多。
所以要dfs出來點的2^k的父親節點與該節點的深度。
找lca時先將下面的點升到與另一點同一深度,再用往上倍增找lca。
有兩種大同小異的方法:一種是以上一步2倍長的步伐向上試,不行再縮減,找到一個離lca能達到的最近點。另一種是先求出最大深度是2的幾次方,再以當前最大步伐向上走。具體看下面程式碼,喜歡哪種打哪種。。。
簡單一題hdu2586
大意是求兩節點距離,只用在dfs時求從根到節點的距離,用L=dis[i]+dis[j]-2*dis[lca(i+j)]求出。
以下程式碼:

#include<stdio.h>
#include<algorithm>
#include<string.h>

using namespace std;

const int maxn=40005;

int tot;
int a[maxn],b[maxn*2],c[maxn*2],w[maxn*2],deep[maxn],dis[maxn],fa[maxn][16];   //注意邊要兩倍空間 
bool bo[maxn];

void setin(int x,int y,int z)           //鄰接表儲存圖 
{
    b[++tot]=a[x];
    a[x]=tot;
    c[tot]=y;
    w[tot]=z;
}

void
dfs(int x) //預處理 { int p,son; p=a[x]; while(p) { son=c[p]; if(!bo[son]) { bo[son]=true; //避免走回去 fa[son][0]=x; deep[son]=deep[x]+1; dis[son]=dis[x]+w[p]; int
ii=0,po=x; while(fa[po][ii]!=0) { fa[son][ii+1]=fa[po][ii]; po=fa[po][ii++]; //關鍵!父節點相當於每次*2,來更新這個子節點的2^k父節點,自己模擬就明白了 } dfs(son); } p=b[p]; } } int lca(int x,int y) { if(x==y) return x; if(deep[x]<deep[y]) swap(x,y); int m=deep[x]-deep[y],ii=0; while(m) //m表示為二進位制,以2,4,8等步伐向上 { if(m&1==1) x=fa[x][ii]; m>>=1; ii++; } ii=0; while(x!=y) if(fa[x][ii]!=fa[y][ii]||((fa[x][ii]==fa[y][ii])&&(ii==0))) //條件很關鍵,僅有一步時要走才能退出迴圈 { x=fa[x][ii]; y=fa[y][ii]; ii++; } else ii--; return x; } int main() { int t,n,q,x,y,z; scanf("%d",&t); for(int i=0;i<t;i++) { tot=0; memset(a,0,sizeof(a)); memset(b,0,sizeof(b)); memset(c,0,sizeof(c)); memset(w,0,sizeof(w)); memset(deep,0,sizeof(deep)); memset(dis,0,sizeof(dis)); memset(fa,0,sizeof(fa)); memset(bo,0,sizeof(bo)); scanf("%d%d",&n,&q); for(int j=0;j<n-1;j++) { scanf("%d%d%d",&x,&y,&z); setin(x,y,z); setin(y,x,z); } deep[1]=1; dis[1]=0; bo[1]=true; dfs(1); for(int j=0;j<q;j++) { scanf("%d%d",&x,&y); printf("%d\n",dis[x]+dis[y]-2*dis[lca(x,y)]); } } }

另一種lca求法:

int lca(int x,int y)
{
    int i,j;
    if(deep[x]<deep[y])swap(x,y);
    for(i=0;(1<<i)<=deep[x];i++);   //求深度是2的幾次方,給下面迴圈找上界 
    i--;
    for(j=i;j>=0;j--)
        if(deep[x]-(1<<j)>=deep[y])
            x=fa[x][j];             //另一種將x提到與y同高度的寫法 
    if(x==y)return x;
    for(j=i;j>=0;j--)
    {
        if(fa[x][j]!=fa[y][j])
        {
            x=fa[x][j];
            y=fa[y][j];
        }
    }
    return fa[x][0];   //注意是把2^k拆成1和其他2的次方,所以返回父節點 
}

ps:因為並不會vector釋放記憶體,就寫了一大串memset,求大神指教如何簡化。

相關推薦

lca倍增演算法學習記錄

找最近公共父節點這問題很容易想到讓兩節點一起往上走最後相遇,但這樣的dfs顯然很慢,於是就需要倍增。就是用二進位制的思維,以1,2,4,8等2的階層步長接近答案,比一步一步向上要快很多。 所以要dfs出來點的2^k的父親節點與該節點的深度。 找lca時先將下

演算法學習記錄

2018.10.17 二維凸包 2018.10.18 樹形DP 2018.10.20 矩陣乘法 2018.10.25 單源最短路,最小生成樹 2018.10.26 並查集,區間DP 2018.11.2 樹狀陣列,無懶標記線段樹 2018.11.4 單調佇列,狀態壓縮DP,網路最大流 2018.11.5 優先佇

lca倍增演算法模板

1431: LCA 最近公共祖先 時間限制: 1 Sec  記憶體限制: 128 MB提交: 244  解決: 36 [提交][狀態] 題目描述 給一棵樹, 節點數為N(1 <= N &

lca倍增演算法

HDU2586 要注意只有簡單邊相連的圖是一棵樹,樹有n-1條邊 倍增之前要先存雙向邊,以任意頂點為根(比如1)dfs遍歷確定樹。 倍增前求f[i,j]時先賦值為-1便於判斷f[ij-1]祖先存不存在 倍增時先將兩個點調至同一高度(注意最後的微調每次只上升一個高度) pro

LCA-Tarjan,RMQ,倍增演算法超詳細原理講解+python實踐(Lowest Common Ancestor of a Binary Tree)

最近公共祖先演算法: 通常解決這類問題有兩種方法:線上演算法和離線演算法 線上演算法:每次讀入一個查詢,處理這個查詢,給出答案 離線演算法:一次性讀入所有查詢,統一進行處理,給出所有答案 我們接下來介紹一種離線演算法:Tarjan,兩種線上演算法:RMQ,倍增演算法 Tarjan

最近公共祖先(LCA) 【倍增演算法

題目連結:洛谷-P3379 ## **題目描述**: 如題,給定一棵有根多叉樹,請求出指定兩個點直接最近的公共祖先。 思路 這是一個裸的LCA問題,即求書上兩個節點的最近公共祖先。 我們可以用樹上倍增來做; 當然,在做之前我們假設不知道該演算法。那麼我們如何來做

資料結構與演算法——學習整理記錄

===注:此文由本人結合網上資源整理總結而來,僅代表個人的學習與理解,如有錯漏,歡迎指正!=== # 1. 資料結構 ## 1.1 資料結構是什麼? 資料結構,直白地理解,就是研究資料的邏輯關係與儲存方式的一門學科。 可以簡單的分為:資料的邏輯結構(邏輯關係)和資料的儲存結構(物理結構

【資料結構與演算法經典問題解析--java語言描述】_第20、21章_學習記錄

【資料結構與演算法經典問題解析--java語言描述】_第20、21章_學習記錄 第20章: 第21章: 1.1  本章主要介紹的是對於面試和考試有用的話題 1.2  位運算的使用 1.2.1 按位與操作

Pow(x, n)演算法實現_學習記錄

pow(x, n)演算法實現_學習記錄 package ps; /** * @author Guozhu Zhu * @date 2018/11/10 * @version 1.0 * */ public class Demo { /* ===========

DP之倍增演算法解決LCA問題

LCA,最近公共祖先,也就是樹上兩個節點的相同的祖先裡距離它們最近的(也就是深度最深的)。倍增演算法用於解決LCA問題的線上查詢。 比如要找x和y的LCA,一般會怎麼做? 首先是暴力。一種是DFS遍歷說有點,無需預處理,查詢是O(n)的。還有一種暴力是先一步一步將x和y提到同一高度,然後

密碼庫LibTomCrypt學習記錄——(2.3)分組密碼演算法的工作模式——ECB程式碼示例

以下程式碼實現了AES-ECB的正確性測試(標準測試資料),以及效能測試 說明: 1. 程式碼裡面使用了一個Str2Num函式,它將測試向量中的字串轉為十六進位制位元組資料,可自行實現。 2. 測試向量出處為NIST SP 800-38A (Recommendation for Bloc

[HDU2586] How far away ?{LCA.tarjan演算法/倍增演算法}

文章目錄 題目 解題思路 程式碼`倍增(TLE)` 程式碼`tarjan演算法(AC)` $tanjan$演算法本質上是使用並查集對“向上標記法”的優化 題目 http://acm.hdu.edu.cn

【資料科學系統學習】機器學習演算法 # 西瓜書學習記錄 [7] 支援向量機(一)

這兩篇內容為西瓜書第 6 章支援向量機 6.1,6.2,6.4,6.3 的內容: 6.1 間隔與支援向量 6.2 對偶問題 6.4 軟間隔與正則化 6.3 核函式 由於本章內容較多,分為兩篇來敘述。本篇所包含內容為間隔與支援向量和對偶問題。 如移動端無法正常

【資料科學系統學習】機器學習演算法 # 西瓜書學習記錄 [8] 支援向量機(二)

這兩篇內容為西瓜書第 6 章支援向量機 6.1,6.2,6.4,6.3 的內容: 6.1 間隔與支援向量 6.2 對偶問題 6.4 軟間隔與正則化 6.3 核函式 由於本章內容較多,分為兩篇來敘述。本篇所包含內容為軟間隔與正則化和核函式。關於間隔與支援向量和

【資料科學系統學習】機器學習演算法 # 西瓜書學習記錄 [9] 決策樹

本篇內容為西瓜書第 4 章決策樹 4.1,4.2,4.3 的內容: 4.1 基本流程 4.2 劃分選擇 4.3 剪枝處理 如移動端無法正常顯示文中的公式,右上角跳至網頁即可正常閱讀。 決策樹 (decision tree) 是一種基本的分類與迴歸方法。在分類問

【資料科學系統學習】機器學習演算法 # 西瓜書學習記錄 [10] 決策樹實踐

本篇內容為《機器學習實戰》第 3 章決策樹部分程式清單。所用程式碼為 python3。 決策樹優點:計算複雜度不高,輸出結果易於理解,對中間值的缺失不敏感,可以處理不相關特徵資料。缺點:可能會產生過度匹配問題。適用資料型別:數值型和標稱型 在構造決策樹時,我們需要

【資料科學系統學習】機器學習演算法 # 西瓜書學習記錄 [11] 整合學習

本篇內容為西瓜書第 8 章整合學習 8.1 8.2 8.3 8.4 8.5 的內容: 8.1 個體與整合 8.2 Boosting 8.3 Bagging與隨機森林 8.4 結合策略 8.5 多樣性 如移動端無法正常顯示文中的公式,右上角跳至網頁即可正常閱讀。

【資料科學系統學習】機器學習演算法 # 西瓜書學習記錄 [12] 整合學習實踐

本篇內容為《機器學習實戰》第 7 章利用 AdaBoost 元演算法提高分類效能程式清單。所用程式碼為 python3。 AdaBoost優點:泛化錯誤率低,易編碼,可以應用在大部分分類器上,無引數調整。缺點:對離群點敏感。適用資料型別:數值型和標稱型資料。 bo

機器學習實戰----kNN近鄰演算法問題記錄

1.import kNN。報錯:only 2 non-keyword arguments accepted 原因:group =array([1.0,1.1],[1.0,1.0],[0,0],[0,0.1]) 粗心少寫了兩個中括號 正確寫法: group=array([

關於CNN行為識別演算法學習記錄

最近需要做一點行為識別相關的專案,於是把行為識別類的演算法(特別是基於CNN的演算法)調研了一遍。 到目前為止,CNN行為識別類的演算法主要都是基於雙流和3D卷積兩種方法,近年來,融合使用光流和C3D的演算法逐漸增多(I3D),也有的演算法使用瞭如RGB Diffieren