poj1330Nearest Common Ancestors(LCA小结)
来源:互联网 发布:mac卡住怎么办 编辑:程序博客网 时间:2024/06/06 08:33
题目请戳这里
题目大意:意如其名。
题目分析:本题只有一个查询,所以可以各种乱搞过去。
不过对于菜鸟而言,还是老老实实练习一下LCA算法。
LCA有很多经典的算法。按工作方式分在线和离线2种。
tarjan算法是经典的离线算法。这篇博客讲的太好懂了,我也不好意思班门弄斧,具体戳进去看看就会明白。重点是那个插图,一看秒懂。
在线算法主要有倍增算法和转RMQ算法。
另外LCA还有2种更为高效的O(n)-O(1)算法。一种请戳这里,另一种其实就是先将LCA转化成RMQ,再利用笛卡尔树O(n)预处理,O(1)回答,具体可以戳这里。
后两种O(n)算法还没有仔细研究,大致看了下,不是很明白,但是感觉很厉害的样子。mark一下,以后抽时间学习一下。
下面给出本题的前3种算法具体实现:
1:tarjan算法(虽然对本题来说有点奢侈了。。)
#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转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]; else dp[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]; else tmp = 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;}
- poj1330Nearest Common Ancestors(LCA小结)
- POJ1330Nearest Common Ancestors最近公共祖先LCA问题
- poj1330Nearest Common Ancestors以及讲解倍增法求lca
- poj1330Nearest Common Ancestors
- POJ1330Nearest Common Ancestors
- poj1330Nearest Common Ancestors(暴力与倍增)
- hdu1470Closest Common Ancestors LCA
- Nearest Common Ancestors--LCA
- POJ1330Nearest Common Ancestors——最近公共祖先(离线Tarjan)
- 1330 Nearest Common Ancestors //LCA
- 1470 Closest Common Ancestors //LCA
- POJ1470 Closest Common Ancestors LCA
- poj1470-Closest Common Ancestors(LCA)
- Closest Common Ancestors(LCA)
- poj1470Closest Common Ancestors(LCA模版)
- poj1470Closest Common Ancestors(lca)
- POJ1330 Nearest Common Ancestors[LCA]
- 【POJ1330】Nearest Common Ancestors(LCA)
- java 多线程同步
- mysql5.6免安装配置
- C++排序之冒泡排序(1)
- 在ARM Linux上使用OpenGL
- mac os x安装git
- poj1330Nearest Common Ancestors(LCA小结)
- remove
- 【Android 应用开发】Android之Bluetooth编程
- 数据结构--广义表
- hdu 3465 Life is a Line 树状数组求逆序数
- 【中国剩余定理】终于弄懂剩余定理了
- 软件工程——用户界面设计
- PHP Static关键字
- 清除session