POJ 1330 Nearest Common Ancestors(求最近的公共祖先)
题意:给出一棵树,再给出两个节点a、b,求离它们最近的公共祖先。
方法一:
先用vector存储某节点的子节点,fa数组存储某节点的父节点,最后找出fa[root]=0的根节点root。
之后求每个节点的“高度”,更节点的高度为1,每往下一层高度+1。
读取a和b后,先求出它们位于同一个高度的祖先:
1.若此祖先相同,则即为最近的公共祖先。
2.若不相同,则求各自的父节点,知道两者的父节点相同,即为最近的公共祖先。
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <vector> using namespace std;
const int maxn=;
int n;
vector<int> son[maxn];
int depth[maxn]; //depth[i]表示节点i的“高度”,这里根节点高度为1,每往下一层高度+1
int fa[maxn]; //fa[i]表示i的父节点 void init(){
for(int i=;i<maxn;i++)
son[i].clear();
memset(depth,,sizeof(depth));
memset(fa,,sizeof(fa));
}
//求出每个节点的“高度”
void dealdepth(int u){
for(int i=;i<son[u].size();i++){
int v=son[u][i];
depth[v]=depth[u]+;
dealdepth(v);
}
return;
} int solve(int a,int b){
//depth[a]>depth[b],表示b在a的上方,先求出a的与b在同一层的祖先
if(depth[a]>depth[b]){
while(depth[a]>depth[b])
a=fa[a];
if(a==b)
return a;
}
//depth[a]<depth[b],表示a在b的上方,先求出b的与a在同一层的祖先
else if(depth[a]<depth[b]){
while(depth[a]<depth[b])
b=fa[b];
if(a==b)
return a;
}
//同时求祖先,直至相等
while(a!=b){
a=fa[a];
b=fa[b];
}
return a;
}
int main()
{
int t,a,b,root,u,v; //root:根节点
scanf("%d",&t);
while(t--){
init();
scanf("%d",&n);
for(int i=;i<n;i++){
scanf("%d%d",&u,&v);
son[u].push_back(v);
fa[v]=u;
}
for(int i=;i<=n;i++){
if(fa[i]==){
root=i;
break;
}
}
depth[root]=;
dealdepth(root);
scanf("%d%d",&a,&b);
int ans=solve(a,b);
printf("%d\n",ans);
}
return ;
}
方法二:用Tarjan算法求
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <string>
#include <vector>
/*
Tarjan算法
*/
using namespace std;
const int maxn=;
int n,t,a,b; //a,b是要求公共祖先的两点
bool flag; //flag为true表明LCA已经求出了a,b的公共祖先,那么就不用继续往下求了
int vis[maxn]; //LCA标记哪些节点已被访问过
int indegree[maxn]; //记录每个节点的入度,用来找寻根节点
int head[maxn];
int tot;
int ans; struct Edge{
int to,next;
}edge[maxn]; void add(int u,int v){
edge[tot].next=head[u];
edge[tot].to=v;
head[u]=tot++;
}
//并查集
struct UF{
int fa[maxn];
void init(){
for(int i=;i<=n;i++)
fa[i]=i;
}
int find_root(int x){
if(fa[x]!=x)
fa[x]=find_root(fa[x]);
return fa[x];
}
void Union(int u,int v){
fa[v]=fa[u];
}
}uf; void LCA(int u){
if(flag)
return;
int v;
for(int k=head[u];k!=-;k=edge[k].next){
v=edge[k].to;
LCA(v);
uf.Union(u,v);
}
vis[u]=; //标记节点u
//看看u是否是查询的两个节点中的一个
if(u==a){
if(vis[b]){
ans=uf.fa[uf.find_root(b)];
flag=true;
}
}
else if(u==b){
if(vis[a]){
ans=uf.fa[uf.find_root(a)];
flag=true;
}
}
}
int main()
{
int root,u,v;
cin>>t;
while(t--){
memset(indegree,,sizeof(indegree));
memset(head,-,sizeof(head));
tot=;
cin>>n;
for(int i=;i<n;i++){
cin>>u>>v;
add(u,v);
indegree[v]++;
}
for(int i=;i<=n;i++){
if(!indegree[i]){
root=i;
break;
}
}
cin>>a>>b;
flag=false;
memset(vis,,sizeof(vis));
uf.init();//一开始忘记初始化了额
LCA(root);
cout<<ans<<endl; }
return ;
}
POJ 1330 Nearest Common Ancestors(求最近的公共祖先)的更多相关文章
- poj 1330 Nearest Common Ancestors 求最近祖先节点
Nearest Common Ancestors Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 37386 Accept ...
- POJ 1330 Nearest Common Ancestors 倍增算法的LCA
POJ 1330 Nearest Common Ancestors 题意:最近公共祖先的裸题 思路:LCA和ST我们已经很熟悉了,但是这里的f[i][j]却有相似却又不同的含义.f[i][j]表示i节 ...
- POJ 1330 Nearest Common Ancestors / UVALive 2525 Nearest Common Ancestors (最近公共祖先LCA)
POJ 1330 Nearest Common Ancestors / UVALive 2525 Nearest Common Ancestors (最近公共祖先LCA) Description A ...
- POJ.1330 Nearest Common Ancestors (LCA 倍增)
POJ.1330 Nearest Common Ancestors (LCA 倍增) 题意分析 给出一棵树,树上有n个点(n-1)条边,n-1个父子的边的关系a-b.接下来给出xy,求出xy的lca节 ...
- POJ - 1330 Nearest Common Ancestors(基础LCA)
POJ - 1330 Nearest Common Ancestors Time Limit: 1000MS Memory Limit: 10000KB 64bit IO Format: %l ...
- LCA POJ 1330 Nearest Common Ancestors
POJ 1330 Nearest Common Ancestors Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 24209 ...
- POJ 1330 Nearest Common Ancestors(lca)
POJ 1330 Nearest Common Ancestors A rooted tree is a well-known data structure in computer science a ...
- POJ 1330 Nearest Common Ancestors 【LCA模板题】
任意门:http://poj.org/problem?id=1330 Nearest Common Ancestors Time Limit: 1000MS Memory Limit: 10000 ...
- POJ 1330 Nearest Common Ancestors(Targin求LCA)
传送门 Nearest Common Ancestors Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 26612 Ac ...
随机推荐
- QQ截图工具提取
今晚关了QQ,突然想截个图,但是呢又不想打开QQ了,于是在网上搜索截图工具,下载了几个,感觉都没有QQ截图好用.索性直接百度QQ截图工具提取,看到有些网站上有提取的,里面的文件有点多,不是我中意的,突 ...
- n盏灯亮灭问题
前几天看了华为的一个上机操作题,讲得是n盏灯亮灭问题,本质上还是数学问题,感觉很有趣,和大家分享一下,问题描述如下: 有n盏灯排成一排,依次标号1,2,…,n,每盏灯都有一根拉线开关,最初电灯都是关着 ...
- 私人定制自己的linux小系统
私人定制自己的linux小系统 一.前言 linux操作系统至1991.10.5号诞生以来,就源其开源性和自由性得到了很多技术大牛的青睐,每个linux爱好者都为其贡献了自己的一份力,不管是在 ...
- CSS3实现半像素边框
一.思路 普通的1px黑色实线边框: border: 1px solid #000; 半像素边框当然不是简单地把1px改为0.5px(没测试过,可能会被解析成1或者0),border-width的值只 ...
- PHP性能优化-编译级别的缓存
最近安装了 php5.6,发现有了 opcache.so扩展文件,于是,搜索了一下,发现 zend opcache已经融入到 ph5.5以上的版本了,即兴奋,不用再去找xcache,apc,eAcce ...
- silverlight 文本框只能输入汉字
private void txtName_KeyDown(object sender, KeyEventArgs e) { Regex rg = new Regex("^[\u4e00-\u ...
- Ubuntu14.04忘记root密码的解决方法
电脑20多天没用忘记密码了,下面是在网上找到的一个解决办法,其它的和这个也大概相同.因为其中有些缺漏,没能给我解决问题.通过分析最终问题还是解决了,现解决方案的关键点记录一下.希望能方便到其它人. 1 ...
- 使用mysql关键字做类字段名报的错,花了我一个钟,坑啊
com.modelsystem.po.ProjectPlan@701faaedHibernate: insert into ld.project_plan (addTime, describe, ex ...
- 忘记linux root密码怎么办?
摘自:<鸟哥的Linux私房菜> 常常有些朋友在配置好了Linux之后,结果root密码给他忘记去!要重新安装吗?不需要的, 你只要以单人维护模式登陆即可更改你的root密码喔!由于lil ...
- About Curah
相信下列场景对您来说一点都不陌生:您遇到一个问题,花了好几个小时在网上搜寻解答和可靠的技术内容.即使前往许多技术博客和论坛翻箱倒柜后,还是无法确定要相信谁,也不知道该选哪个答案. Curah! 网站就 ...