树的最近公共祖先——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
原创粉丝点击