树的最近公共祖先——LCA poj1330 hdu2586
来源:互联网 发布:linux中国开源社区 编辑:程序博客网 时间:2024/05/01 03:25
树的最近公共祖先问题,是指给定一棵有向树(无向的可以转化为有向的),对于询问q(u,y),返回u和v的最近公共祖先。
解决问题算法可以分为在线算法和离线算法。
离线算法思想:
离线算法需要预先将所有的询问存起来,等到dfs的时候一下逐一输出结果。
dfs对树进行遍历,当某个节点u的一个子树全部遍历完以后,就更新这棵子树的节点的父节点为u(转化为并查集:将该子树集合加入到u所在的集合中,并更新子树集合的父亲为u)如果当前节点x是被询问到的节点,并且一直相关的(询问了x,y的最近公共祖先)另一个节y点已经搜索过,则x与y的最近公共祖先为y此时的父亲。
在线算法的思想:
在线算法的思想比较简单,先对整棵树进行dfs,并记下每个节点的深度以及父节点,当询问某对节点时,比较两个节点的深度,深度大的节点开始沿着父节点往回走,当两个节点的深度相同时,判断其是否为同一个节点,若是,则输出,否则,两节点同时沿着各自的父亲节点往回走,直到两节点相同,输出。
个比较喜欢用在线算法,而且优化后速度也很快。
刚开始学习这个算法的时候也在网上找了许多资料,但是还是觉得这片文章写得很好;
http://blog.csdn.net/v_july_v/article/details/18312089
看完算法后,我自己也找了几道简单的题目做了做;
poj1330 离线算法
#include<cstdio>#include<cstring>#include<vector>#define MAX 10010using namespace std;vector<int>G[MAX];int fa[MAX],lca[MAX],c[MAX],vis[MAX],u,v,ans;int find(int x){ //并查集 return x == fa[x] ? x : (fa[x] = find(fa[x]));}void merge(int x, int y){ x = find(x); y = find(y); if (x != y) fa[x] = y;}void LCA(int root){ //最近公共祖先 for (int i = 0; i<G[root].size(); i++){ LCA(G[root][i]); merge(G[root][i],fa[root]); //如何合并? } vis[root] = 1; if (root == u && vis[v]){ printf("%d\n",find(v)); return; } else if (root == v && vis[u]){ printf("%d\n",find(u)); return; }}int main(){ int T,n,root; scanf("%d",&T); while (T--){ scanf("%d",&n); //初始化并输入数据 for (int i = 0; i<MAX; i++) G[i].clear(); memset(c,0,sizeof(c)); memset(vis,0,sizeof(vis)); for (int i = 1; i<=n; i++){ fa[i] = i; lca[i] = i; } int a,b; for (int i = 0; i<n-1; i++){ scanf("%d%d",&a,&b); c[b]++; G[a].push_back(b); } for (int i = 1; i<=n; i++) if (c[i] == 0){ //找到根节点 root = i; break; } scanf("%d%d",&u,&v); LCA(root); } return 0;}hdu2586在线算法;
#include<cstdio>#include<cstring>#include<vector>#include<algorithm>#define MAX 40010using namespace std;struct Edge{int from,to,dist;};vector<int>G[MAX];vector<Edge>edges;int D[MAX], d[MAX], fa[MAX], in[MAX];bool vis[MAX];void init(){edges.clear();for (int i=0; i<MAX; i++) G[i].clear();memset(vis,false,sizeof(vis));memset(d,0,sizeof(d));memset(in,0,sizeof(in));}void AddEdge(int from, int to, int dist){edges.push_back((Edge){from,to,dist});int k = edges.size();G[from].push_back(k-1);}void dfs(int pa, int u, int depth){D[u] = depth;vis[u] = true;fa[u] = pa;for (int i=0; i<G[u].size(); i++){Edge& e = edges[G[u][i]];if (vis[e.to]) continue;d[e.to] = d[u] + e.dist;dfs(u,e.to,depth+1);}}int LCA(int u, int v){int x = D[u];int y = D[v];if (x < y) {swap(u,v);swap(x,y);}while (x > y){u = fa[u];x--;}if (u == v) return v;while (u != v){u = fa[u];v = fa[v];}return v;}int main(){int T,n,m;scanf("%d",&T);while (T--){init();scanf("%d%d",&n,&m);int x,y,z;for (int i = 1; i<n; i++){scanf("%d%d%d",&x,&y,&z);in[y]++;AddEdge(x,y,z);}int root;for (int i = 1; i<=n; i++) if (!in[i]){root = i;break;}dfs(-1,root,0);//for (int i = 1; i<=n; i++) printf("%d ",D[i]); printf("\n");int u,v;for (int i = 0; i<m; i++){scanf("%d%d",&u,&v);int w = LCA(u,v);printf("%d\n",d[u]+d[v]-2*d[w]);}}return 0;}
hdu2586在线算法 + ST优化;
#include<cstdio>#include<cstring>#include<vector> #include<algorithm>#define MAX 80010 using namespace std;struct Edge{int form, to, dist;};int E[MAX],D[MAX],R[MAX],in[MAX],dp[MAX][30],d[MAX],cnt; //cnt = -1bool vis[MAX];vector<int>G[MAX];vector<Edge>edges;void AddEdge(int from, int to, int dist){ edges.push_back((Edge){from,to,dist});int k = edges.size();G[from].push_back(k-1);}void dfs(int fa, int u, int depth){E[++cnt] = u;D[u] = depth;R[u] = cnt;vis[u] = true;for (int i = 0; i<G[u].size(); i++){Edge& e = edges[G[u][i]];if (vis[e.to]) continue;d[e.to] = d[u] + e.dist;dfs(u,e.to,depth+1);E[++cnt] = u;}}void RMQ(){for (int i = 0; i < cnt; i++) dp[i][0] = E[i];for (int j = 1; (1<<j) < cnt; j++){for (int i = 0; i<cnt-(1<<j)+1; i++){if (D[dp[i][j-1]] <= D[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 LCA(int u, int v){u = R[u];v = R[v];if (u > v) swap(u,v);int k = 0;while ((1<<k) <= (v-u+1)) k++;k--;if (D[dp[u][k]] < D[dp[v-(1<<k)+1][k]]) return dp[u][k];return dp[v-(1<<k)+1][k];}int main(){int T,n,m;scanf("%d",&T);while (T--){edges.clear();for (int i = 0; i<MAX; i++) G[i].clear();memset(vis,false,sizeof(vis));memset(in,0,sizeof(in));cnt = -1;scanf("%d%d",&n,&m);int x,y,z;for (int i = 1; i<n; i++){scanf("%d%d%d",&x,&y,&z);in[y]++;AddEdge(x,y,z);}int root;for (int i = 1; i<=n; i++) if (!in[i]){root = i;break;}dfs(-1,root,0);//for (int i = 1; i<=n; i++) printf("%d ",d[i]); printf("\n");cnt += 1; RMQ();int u, v;for (int i = 0; i<m; i++){scanf("%d%d",&u,&v);int w = LCA(u,v);printf("%d\n",d[u] + d[v] - 2*d[w]);}}return 0;}
0 0
- 树的最近公共祖先——LCA poj1330 hdu2586
- hdu2586(LCA最近公共祖先)
- poj1330(LCA最近公共祖先)
- 【LCA倍增模板】【poj1330】最近公共祖先
- POJ1330(最近公共祖先)
- POJ1330最近公共祖先
- POJ1330 最近公共祖先
- POJ1330 最近公共祖先
- HDU2586(最近公共祖先的Tarjan算法)
- HDU2586 How far away ?【最近公共祖先】【Tarjan-LCA算法】
- 【POJ1330】最近公共祖先(LCA):并查集+深搜
- POJ1330 Nearest Common Ancestors【最近公共祖先】【Tarjan-LCA算法】
- 【POJ1330】最近公共祖先(LCA):并查集+深搜
- poj1330——Nearest Common Ancestors(最近公共祖先)
- 二叉树的最近公共祖先LCA
- 【算法】【树】最近公共祖先LCA——Tarjan算法
- hdu2586(最近公共祖先)
- POJ1330最近的祖先
- 第一轮 D
- 安装oracle时出现不满足256色的错误解决方法
- 教你怎么使用apilication—纪念火影-->影子模仿术
- 小马哥-----高仿华为荣耀3c 6572芯片详细拆机 主板图 开 真假机鉴别
- Diverse Permutation - CodeForces 482 A 水题
- 树的最近公共祖先——LCA poj1330 hdu2586
- ubuntu下编译java程序
- 就从这里出发
- android Bound Service使用:使用Message类绑定服务
- 我为何停止使用Spring
- Android递归删除文件和文件夹(转载)
- ADF备忘:EL表达式调用带参数的方法(expression language invoke method with parameter)
- 找出2N+1个两两配对数中落单那个
- Leetcode: Min Stack