محاسبهی پایینترین جد مشترک
تعریف
در نظریه گراف و علومکامپیوتر پایینترین جد مشترک برای دو راس مثل
مثلا در شکل زیر راس
الگوریتم
سادهترین راهی که به ذهن میرسد این است که به ازای هر پرسش
سپس تا زمانی که دو راس برابر نشدند در هر مرحله هر دو را یکی بالا میاوریم. از آنجایی که راس ریشه جد مشترک آنهاست این فرایند حتما متوقف میشود و راسی که در آن متوقف شدیم پایینترین راسیاست که جد مشترک
ایدهایی که برای بهبود عملکرد این الگوریتم به ذهن میرسد استفاده از روشی است که i-امین راس بالای هر راس دلخواه را در مرتبهی خوبی در اختیار ما قرار بدهد.
مقدار
- به ازای هر v و i = 0 مقدار
است. - به ازای هر i ناصفر
است.
در قسمت اول الگوریتم ابتدا لازم بود که v و u را هم ارتفاع کنیم، میتوانیم برای پیدا کردن x-امین راس بالای v با گامهای به اندازهی
الگوریتم تارجان
پیادهسازی
- LCA.cpp
#include <iostream> #include <vector> using namespace std; const int MAXN = 100 * 1000 + 1; const int MAX_LG_N = 17 + 1; const int MAXM = 100 * 1000; int ancestor[MAXN][MAX_LG_N]; int father[MAXN]; int n, m; int query[MAXM][2]; int answer[MAXM]; int depth[MAXN]; vector<int> child[MAXN]; bool dfs_mark[MAXN]; void dfs(int v); int up(int v, int dist); void input(); void preprocess(); int calculate_lca(int v, int u); int main(){ // get tree from input cin >> n; for(int i = 2; i <= n; i++){ cin >> father[i]; child[ father[i] ].push_back(i); } for(int i = 1; i <= m; i++) cin >> query[i][0] >> query[i][1]; preprocess(); // get queries form input and print answers cin >> m; for(int i = 1; i <= m; i++){ int v, u; cin >> v >> u; cout << calculate_lca(v, u) << endl; } return 0; } void preprocess(){ // calculate ancestor[v][i] father[1] = 1; // father[root] = root for(int i = 1; i <= n; i++) ancestor[i][0] = father[i]; for(int j = 1; j < MAX_LG_N; j++) for(int i = 1; i <= n; i++) ancestor[i][j] = ancestor[ ancestor[i][j-1] ][j-1]; // calculate depth[v] dfs(1); // dfs(root) } int calculate_lca(int v, int u){ if(depth[v] > depth[u]) swap(u, v); // to sure depth[v] < depth[u] u = up(u, depth[u] - depth[v]); for(int j = MAX_LG_N - 1; j >= 0; j--) if(ancestor[u][j] != ancestor[v][j]){ u = ancestor[u][j]; v = ancestor[v][j]; } if(u == v) return v; return ancestor[v][0]; } void dfs(int v){ dfs_mark[v] = true; for(int i = 0; i < child[v].size(); i++){ int u = child[v][i]; if(!dfs_mark[u]){ depth[u] = depth[v] + 1; dfs(u); } } } int up(int v, int dist){ for(int i = MAX_LG_N - 1; i >= 0; i--) if(dist >= (1 << i)){ v = ancestor[v][i]; dist -= (1 << i); } return v; }
مسائل نمونه
- superviva [سطح: متوسط]