poj 1330 Nearest Common Ancestors
2016-08-05 15:36
393 查看
题目大意
给t组数据,每组数据给出n个节点和n-1条边的信息构成一棵树,再给出一对节点u和v,求u和v的最近公共祖先。
算法思想:找LCA,分在线算法(每读入一组点对就进行一次查找)和离线算法(把所有点对都存下来,全部读入完后再组团找LCA)。
提示:此题很水,因为每组数据只有一组点对,所以不用标准的LCA查找算法也能过,而且跑得还快。。。可以用Tarjan,倍增查找也行。
样例数据
input
output
给t组数据,每组数据给出n个节点和n-1条边的信息构成一棵树,再给出一对节点u和v,求u和v的最近公共祖先。
算法思想:找LCA,分在线算法(每读入一组点对就进行一次查找)和离线算法(把所有点对都存下来,全部读入完后再组团找LCA)。
提示:此题很水,因为每组数据只有一组点对,所以不用标准的LCA查找算法也能过,而且跑得还快。。。可以用Tarjan,倍增查找也行。
样例数据
input
2 16 1 14 8 5 10 16 5 9 4 6 8 4 4 10 1 13 6 15 10 11 6 7 10 2 16 3 8 1 16 12 16 7 5 2 3 3 4 3 1 1 5 3 5
output
4 3
#include<iostream> #include<algorithm> #include<cmath> #include<vector> #include<memory.h> using namespace std; int n,fa[10010],r[10010],anc[10010],num[10010]; bool vis[10010]; vector<int>node[10010],q[10010]; void main_pre(int n) { for (int i=1;i<=n;i++) { fa[i]=i; r[i]=0; node[i].clear(); q[i].clear(); } memset(vis,false,sizeof(vis)); memset(num,0,sizeof(num)); //入度; memset(anc,0,sizeof(anc)); //祖先; } int get(int x) { if(fa[x]==x) return x; else return get(fa[x]); } void unit(int x,int y) { int f1=get(x),f2=get(y); if (f1!=f2) { if (r[f1]<r[f2]) fa[f1]=f2; else fa[f2]=f1; if (r[f1]==r[f2]) r[f2]++; } } void LCA(int x) { anc[x]=x; for (int i=0;i<node[x].size();i++) { LCA(node[x][i]); unit(x,node[x][i]); int k=get(node[x][i]); anc[k]=x; } vis[x]=1; for (int i=0;i<q[x].size();i++) { if (vis[q[x][i]]) cout<<anc[get(q[x][i])]<<endl; } return; } int main() { int t,n,x,y; scanf("%d",&t); while (t--) { scanf("%d",&n); main_pre(n); //初始化; //建树---------------------------------------------- for (int i=1;i<n;i++) { int x,y; scanf("%d%d",&x,&y); node[x].push_back(y); num[y]++; } //存储要查找的点对(x,y),这道题只有一对---------- scanf("%d%d",&x,&y); q[x].push_back(y); q[y].push_back(x); //找根节点----------------------------------------- int root; for (int i=1;i<=n;i++) { if (!num[i]) { root=i; break; } } //组团查询LCA-------------------------------------- LCA(root); } return 0; }
倍增查找:
#include<iostream> #include<algorithm> #include<cmath> #include<cstring> using namespace std; int f[10005][25],fa[10005]; int d[10005],ans=0,n; void pre() { for (int i=1;i<=n;i++) f[i][0]=fa[i]; for (int j=1;j<=20;j++) for (int i=1;i<=n;i++) f[i][j]=f[f[i][j-1]][j-1]; } void get(int x) { if (fa[x]==x) return; else { ans++; get(fa[x]); } } void _find(int x,int y) { int d1=d[x],d2=d[y]; if (d1>d2) swap(x,y); int k=20; while (d[y]>d[x]) { for (int i=k;i>=0;i--) { if (d[f[y][i]]>=d[x]) { y=f[y][i]; k=i; break; } } } if(x==y) { cout<<x<<endl; return; } bool ff=1; k=20; while (ff) { if (f[x][0]==f[y][0]) break; for (int i=k;i>=0;i--) { if (f[x][i]!=f[y][i]) { x=f[x][i]; y=f[y][i]; k=i; break; } } } cout<<f[x][0]<<endl; return; } int main() { int t,x,y; cin>>t; while (t--) { memset(fa,0,sizeof(fa)); memset(d,0,sizeof(d)); memset(f,0,sizeof(f)); cin>>n; for (int i=1;i<n;i++) { cin>>x>>y; fa[y]=x; } pre(); for (int i=1;i<=n;i++) { ans=0; get(i); d[i]=ans; } cin>>x>>y; _find(x,y); } }
相关文章推荐
- 初学ACM - 组合数学基础题目PKU 1833
- POJ ACM 1001
- POJ ACM 1002
- 二叉树求最大最小叶子节点距离
- 1611:The Suspects
- POJ1089 区间合并
- POJ 2159 Ancient Cipher
- POJ 2635 The Embarrassed Cryptographe
- POJ 3292 Semi-prime H-numbers
- POJ 2773 HAPPY 2006
- POJ 3090 Visible Lattice Points
- LCA模板
- POJ-2409-Let it Bead&&NYOJ-280-LK的项链
- POJ-1695-Magazine Delivery-dp
- POJ1523 SPF dfs
- POJ-1001 求高精度幂-大数乘法系列
- POJ-1003 Hangover
- POJ-1004 Financial Management
- [数论]poj2635__The Embarrassed Cryptographer
- [二分图匹配]poj2446__Chessboard