LCA最近公共祖先(朴素+倍增法)
来源:互联网 发布:图表数据区域格式 编辑:程序博客网 时间:2024/05/16 10:49
<span style="color: rgb(51, 51, 51); font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 18px; font-weight: bold; line-height: 1.42857143; background-color: rgb(255, 255, 255);">样例输入</span>
4Adam SamSam JoeySam MichealAdam Kevin3Sam SamAdam SamMicheal Kevin
SamAdamAdam给出n个父子关系,然后接着m个询问,问两者的最近公共祖先是哪个。
下面的是用的很直白的搜索。每次找到两点的深度,然后将两点升到相同的高度。升到相同的高度后继续一起向上升。直到升到祖先相同。算法复杂度是O(dep[u]+dep[v]) ,最大深度为n,所以算法复杂度为O(n);
听起来还不错是吧~
But..
还有m 个询问啊,m如果很大。酱紫肯定TLE啊。下面的代码就是T的。。。
不过,肯定会有办法解决的是吧~
#include <cstdio>#include <cstring>#include <cmath>#include <iostream>#include <vector>#include <map>#include <algorithm>#define read freopen("q.in","r",stdin)#define LL long long#define maxn 100005using namespace std;int fa[maxn],dep[maxn],dg[maxn];map<string,int> mp;map<int,string> remp;vector<int> vt[maxn];void dfs(int x,int p,int d){fa[x]=p;dep[x]=d;int i,j;for(i=0;i<vt[x].size();i++)dfs(vt[x][i],x,d+1);}int lca(int u,int v){int i,j;while(dep[u]>dep[v])u=fa[u];while(dep[v]>dep[u])v=fa[v];while(u!=v){u=fa[u];v=fa[v];}return u;}int main(){int n,u,v,cnt=1;int root,i,q;string father,son;memset(dg,0,sizeof(dg));scanf("%d",&n);while(n--){cin>>father>>son;if(!mp[father]){mp[father]=cnt;remp[cnt]=father;cnt++;}if(!mp[son]){mp[son]=cnt;remp[cnt]=son;cnt++;}u=mp[father];v=mp[son];vt[u].push_back(v);dg[v]++;}for(i=1;i<cnt;i++)if(dg[i]==0){root=i;break;}dfs(root,-1,0);scanf("%d",&q);while(q--){cin>>father>>son;int res=lca(mp[father],mp[son]);cout<<remp[res]<<endl;}}那既然,一步一步的走太慢,干脆在计算机中还经常logn,那就利用这点来加快速度吧。
fa[k][v]表示每次向上走k步,k是2的幂,k最大取log(n),分别计算可以走的步伐的父亲,然后从最长的步伐开始尝试。这样就可以快很多辣~
#include <cstdio>#include <cstring>#include <cmath>#include <iostream>#include <vector>#include <map>#include <algorithm>#define read freopen("q.in","r",stdin)#define LL long long#define maxn 100005#define maxlog (log(maxn)/log(2))using namespace std;int fa[100][maxn],dep[maxn],dg[maxn];map<string,int> mp;map<int,string> remp;vector<int> vt[maxn];int cnt,root;void dfs(int x,int p,int d){fa[0][x]=p;dep[x]=d;int i,j;for(i=0;i<vt[x].size();i++)dfs(vt[x][i],x,d+1);}void init(){int i,mlog=(log(cnt)/log(2));dfs(root,-1,0);for(int k=0;k+1<mlog;k++){for(int v=0;v<cnt;v++){if(fa[k][v]<0)fa[k+1][v]=-1;else fa[k+1][v]=fa[k][fa[k][v]];}}}int lca(int u,int v){int i,j,mlog=(log(cnt)/log(2));;if(dep[u]>dep[v])swap(u,v);for(i=0;i<mlog;i++){if((dep[v]-dep[u])>>i &1)v=fa[i][v];}if(u==v)return u;for(int k=mlog-1;k>=0;k--){if(fa[k][u]!=fa[k][v]){u=fa[k][u];v=fa[k][v];}}return fa[0][u];}int main(){//read;int n,u,v;cnt=1;int i,q;string father,son;memset(dg,0,sizeof(dg));scanf("%d",&n);while(n--){cin>>father>>son;if(!mp[father]){mp[father]=cnt;remp[cnt]=father;cnt++;}if(!mp[son]){mp[son]=cnt;remp[cnt]=son;cnt++;}u=mp[father];v=mp[son];vt[u].push_back(v);dg[v]++;}for(i=1;i<cnt;i++)if(dg[i]==0){root=i;break;}init();scanf("%d",&q);while(q--){cin>>father>>son;int res=lca(mp[father],mp[son]);cout<<remp[res]<<endl;}}
其实,解决lca问题的算法很多,除了这两种之外还有
一种叫tajian的算法,以及转化成RMQ的问题。
这些算法,以后再写。一篇博客不能太长。不然就太无趣辣,反正我忍受不了太长的博客。。。
0 0
- LCA最近公共祖先(朴素+倍增法)
- 最近公共祖先(LCA)---倍增法
- 倍增法求最近公共祖先 lca
- 最近公共祖先(LCA):倍增
- LCA(最近公共祖先)倍增法模板及总结
- LCA(最近公共祖先)倍增法实现
- 倍增法求最近公共祖先(LCA)
- 最近公共祖先(LCA)之树上倍增法
- LCA 在线倍增法 求最近公共祖先
- 【讲解+模板】最近公共祖先(LCA)(倍增)
- 最近公共祖先(LCA):tarjan与倍增
- 树上倍增求LCA(最近公共祖先)
- lca(最近公共祖先)倍增模板【pascal】
- lca最近公共祖先(st表/倍增)
- 最近公共祖先(LCA)及其倍增算法实现
- 洛谷 3379 最近公共祖先(LCA 倍增)
- c++最近公共祖先LCA(倍增算法和tarjan)
- 倍增LCA(最近公共祖先)算法详解
- 随便抄一点
- 杭电 HDU ACM 1421 搬寝室
- [leetcode]Maximum Product Subarray
- support for cores revisions 0x17 and 0x18 disabled by module param allhwsupport=0.
- 简单计算器 HDU 1237
- LCA最近公共祖先(朴素+倍增法)
- ZOJ 3872 Beauty of Array(模拟)
- hdu 1114 Piggy-Bank
- 使用pentaho report 开发web报表
- telnet命令行使用
- 黑马程序员——多线程
- App工程结构搭建:几种常见Android代码架构分析
- 何新生的英语史(一)—蹉跎岁月
- 我要驯服java