日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

poj1330Nearest Common Ancestors(LCA小结)

發(fā)布時(shí)間:2024/1/17 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 poj1330Nearest Common Ancestors(LCA小结) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

題目請(qǐng)戳這里

題目大意:意如其名。

題目分析:本題只有一個(gè)查詢,所以可以各種亂搞過(guò)去。

不過(guò)對(duì)于菜鳥(niǎo)而言,還是老老實(shí)實(shí)練習(xí)一下LCA算法。

LCA有很多經(jīng)典的算法。按工作方式分在線和離線2種。

tarjan算法是經(jīng)典的離線算法。這篇博客講的太好懂了,我也不好意思班門(mén)弄斧,具體戳進(jìn)去看看就會(huì)明白。重點(diǎn)是那個(gè)插圖,一看秒懂。

在線算法主要有倍增算法和轉(zhuǎn)RMQ算法。

另外LCA還有2種更為高效的O(n)-O(1)算法。一種請(qǐng)戳這里,另一種其實(shí)就是先將LCA轉(zhuǎn)化成RMQ,再利用笛卡爾樹(shù)O(n)預(yù)處理,O(1)回答,具體可以戳這里。

后兩種O(n)算法還沒(méi)有仔細(xì)研究,大致看了下,不是很明白,但是感覺(jué)很厲害的樣子。mark一下,以后抽時(shí)間學(xué)習(xí)一下。

下面給出本題的前3種算法具體實(shí)現(xiàn):

1:tarjan算法(雖然對(duì)本題來(lái)說(shuō)有點(diǎn)奢侈了。。)

?

#include <iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N = 10005; struct node {int to,next; }e[N]; int head[N],set[N],fa[N],in[N]; bool vis[N]; int n,num,p,q; void build(int s,int ed) {e[num].to = ed;e[num].next = head[s];head[s] = num ++; } void init() {num = 0;memset(head,-1,sizeof(head));memset(in,0,sizeof(in)); } int find(int x) {int rt = x;while(set[rt] != rt)rt = set[rt];int pa = set[x];while(pa != rt){set[x] = rt;x = pa;pa = set[x];}return rt; } void bing(int a,int b) {int ra = find(a);int rb = find(b);if(ra != rb)set[rb] = ra; } void dfs(int cur) {fa[cur] = cur;set[cur] = cur;int i;for(i = head[cur];i != -1;i = e[i].next){dfs(e[i].to);bing(cur,e[i].to);fa[find(cur)] = cur;}vis[cur] = true;if((p == cur && vis[q]))printf("%d\n",fa[find(q)]);if((q == cur && vis[p]))printf("%d\n",fa[find(p)]); } void tarjan() {int i;memset(vis,false,sizeof(vis));for(i = 1;i <= n;i ++)if(in[i] == 0)break;dfs(i); } int main() {int t;int i,a,b;scanf("%d",&t);while(t --){scanf("%d",&n);init();for(i = 1;i < n;i ++){scanf("%d%d",&a,&b);build(a,b);in[b] ++;}scanf("%d%d",&p,&q);tarjan();}return 0; }


2:LCA轉(zhuǎn)RMQ,再st算法:

?

?

#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; const int N = 20005;int dep[N],pos[N],seq[N],first[N],in[N]; int dp[N][20]; struct node {int to,next; }e[N]; int head[N]; int n,num,p,q,id; void build(int s,int ed) {e[num].to = ed;e[num].next = head[s];head[s] = num ++; }void dfs(int cur,int deep) {dep[cur] = deep;first[cur] = id;pos[id] = cur;seq[id ++] = dep[cur];int i;for(i = head[cur];i != -1;i = e[i].next){dfs(e[i].to,deep + 1);pos[id] = cur;seq[id ++] = dep[cur];} } int rmq() {int i,j;for(i = 1;i <= id;i ++)dp[i][0] = i;for(j = 1;(1<<j) <= id;j ++){for(i = 1;(i + (1<<(j - 1))) <= id;i ++)if(seq[dp[i][j - 1]] < seq[dp[i + (1<<(j - 1))][j - 1]])dp[i][j] = dp[i][j - 1];elsedp[i][j] = dp[i + (1<<(j - 1))][j - 1];}int tp = first[p];int tq = first[q];if(tp > tq)swap(tp,tq);int k = floor(log((double)(tq - tp + 1))/log(2.0));int tmp;if(seq[dp[tp][k]] < seq[dp[tq - (1<<k) + 1][k]])tmp = dp[tp][k];elsetmp = dp[tq - (1<<k) + 1][k];return pos[tmp]; } void solve() {int i;id = 1;for(i = 1;i <= n;i ++)if(in[i] == 0)break;dfs(i,0);id --;printf("%d\n",rmq()); } int main() {int i,a,b,t;freopen("in.txt","r",stdin);scanf("%d",&t);while(t --){scanf("%d",&n);num = 0;memset(head,-1,sizeof(head));memset(in,0,sizeof(in));for(i = 1;i < n;i ++){scanf("%d%d",&a,&b);build(a,b);in[b] ++;}scanf("%d%d",&p,&q);solve();}return 0; }


3:倍增算法:

?

?

#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N = 10005;int dp[N][20],deep[N]; struct node {int to,next; }e[N]; int n,num,p,q; int head[N],in[N]; void build(int s,int ed) {e[num].to = ed;e[num].next = head[s];head[s] = num ++; } void dfs(int cur,int fa) {deep[cur] = deep[fa] + 1;dp[cur][0] = fa;int i;for(i = 1;i < 18;i ++)dp[cur][i] = dp[dp[cur][i - 1]][i - 1];for(i = head[cur];i != -1;i = e[i].next){dfs(e[i].to,cur);} } int lca() {if(deep[p] < deep[q])swap(p,q);int i,j;for(j = deep[p] - deep[q],i = 0;j;j >>= 1,i ++){if(j&1)p = dp[p][i];}if(p == q)return q;for(i = 18;i >= 0;i --){if(dp[p][i] != dp[q][i]){p = dp[p][i];q = dp[q][i];}}return dp[q][0]; } void solve() {int i;memset(deep,0,sizeof(deep));for(i = 1;i <= n;i ++)if(in[i] == 0)break;dfs(i,0);printf("%d\n",lca()); } int main() {int t,i,a,b;freopen("in.txt","r",stdin);scanf("%d",&t);while(t --){scanf("%d",&n);num = 0;memset(head,-1,sizeof(head));memset(in,0,sizeof(in));for(i = 1;i < n;i ++){scanf("%d%d",&a,&b);build(a,b);in[b] ++;}scanf("%d%d",&p,&q);solve();}return 0; }


?

?

總結(jié)

以上是生活随笔為你收集整理的poj1330Nearest Common Ancestors(LCA小结)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。