POJ 1330 Nearest Common Ancestors(LCA,在线处理三种方式)
来源:互联网 发布:我与网络强国演讲稿 编辑:程序博客网 时间:2024/06/03 21:10
题目链接:
POJ 1330 Nearest Common Ancestors
题意:
给一个
数据范围:
分析:
可以学习《挑战程序设计竞赛》
暴力求解
记节点
时间复杂度:
#include <stdio.h>#include <string.h>#include <math.h>#include <algorithm>using namespace std;typedef long long ll;const int MAX_N = 10010;int T, n, total, root;int head[MAX_N], in[MAX_N], fa[MAX_N], depth[MAX_N];struct Edge { int v, next;}edge[MAX_N];void AddEdge(int u, int v) { edge[total].v = v; edge[total].next = head[u]; head[u] = total++;}void dfs(int u, int p, int cur){ fa[u] = p; depth[u] = cur; for (int i = head[u]; i != -1; i = edge[i].next) { dfs (edge[i].v, u, cur + 1); }}int LCA(int u, int v){ while (depth[u] > depth[v]) u = fa[u]; while (depth[v] > depth[u]) v = fa[v]; while (u != v) { u = fa[u]; v = fa[v]; } return u;}int main(){ scanf("%d", &T); while (T--) { total = 0; memset(head, -1, sizeof (head)); memset(in, 0, sizeof (in)); scanf("%d", &n); int u, v; for (int i = 1; i <= n; ++i) { scanf("%d%d", &u, &v); if (i != n) { AddEdge(u, v); in[v]++; } } for (int i = 1; i <= n; ++i) { if (in[i] == 0) { root = i; break; } } dfs (root, -1, 0); printf("%d\n", LCA(u, v)); } return 0;}
二分搜索
首先对于任意节点
预处理
#include <stdio.h>#include <string.h>#include <algorithm>#include <math.h>using namespace std;typedef long long ll;const int MAX_N = 10010;const int MAX_LOG_N = 20; // MAX_LOG_N = log2(MAX_N)int T, n, total, root;int head[MAX_N], in[MAX_N], depth[MAX_N], fa[MAX_N][MAX_LOG_N];struct Edge { int v, next;}edge[MAX_N];void AddEdge(int u, int v){ edge[total].v = v; edge[total].next = head[u]; head[u] = total++;}void dfs(int u, int p, int d){ // 获取每个节点的深度和直接父亲 depth[u] = d; fa[u][0] = p; for (int i = head[u]; i != -1; i = edge[i].next) { dfs(edge[i].v, u, d + 1); }}void RMQ() // 时间复杂度: O(nlog(n)){ // 倍增处理每个节点的祖先 for (int k = 0; k + 1 < MAX_LOG_N; ++k) { for (int i = 1; i <= n; ++i) { if (fa[i][k] == -1) fa[i][k + 1] = -1; else fa[i][k + 1] = fa[fa[i][k]][k]; } } }int LCA(int u, int v) // 时间复杂度:O(log(n)){ // 先把两个节点提到同一深度 if (depth[u] > depth[v]) swap(u, v); for (int k = 0; k < MAX_LOG_N; ++k) { if (((depth[v] - depth[u]) >> k) & 1) { v = fa[v][k]; } } if (u == v) return v; // 二分搜索计算LCA for (int k = MAX_LOG_N - 1; k >= 0; --k) { if (fa[u][k] != fa[v][k]) { u = fa[u][k]; v = fa[v][k]; } } return fa[u][0];}int main(){ scanf("%d", &T); while (T--) { memset(head, -1, sizeof (head)); memset(in, 0, sizeof(in)); memset(depth, 0, sizeof(depth)); memset(fa, -1, sizeof(fa)); total = 0; scanf("%d", &n); int u, v; for (int i = 1; i <= n; ++i) { scanf("%d%d", &u, &v); if (i != n) { AddEdge(u, v); in[v]++; } } // 找到根节点 for (int i = 1; i <= n; ++i) { if (in[i] == 0) { root = i; break; } } dfs(root, -1, 0); RMQ(); printf("%d\n", LCA(u, v)); } return 0;}
基于RMQ的算法
其实上面的二分搜索算法已经有了
将树转为从根
首先按从根
预处理:
#include <stdio.h>#include <string.h>#include <math.h>#include <algorithm>using namespace std;typedef long long ll;const int MAX_N = 10010;int T, n, total;int head[MAX_N], vis[MAX_N * 2], id[MAX_N], depth[MAX_N * 2], dp[MAX_N * 2][20], in[MAX_N];struct Edge { int v, next;} edge[MAX_N * 2];void AddEdge (int u, int v){ edge[total].v = v; edge[total].next = head[u]; head[u] = total++;}void dfs(int u, int p, int d, int& k){ vis[k] = u; // dfs访问顺序 id[u] = k; // 节点在vis中首次出现的下标 depth[k++] = d; // 节点对应的深度 for (int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].v; if (v == p) continue; dfs(v, u, d + 1, k); // 递归访问子节点 vis[k] = u; // 再次访问 depth[k++] = d; // 标记vis的深度 }}void RMQ(int root) // 处理区间深度最小值,保存最小值的下标{ // 就是区间左右端点最近公共祖先的下标,即:vs[Min] = LCA int k = 0; dfs(root, -1, 0, k); // printf ("k = %d\n", k); int m = k; // m = 2 * n - 1 int e = (int)(log2(m + 1.0)); // 区间长度m + 1 for (int i = 0; i < m; ++i) dp[i][0] = i; for (int j = 1; j <= e; ++j) { for (int i = 0; i + (1 << j) - 1 < m; ++i) { int nxt = i + (1 << (j - 1)); if (depth[dp[i][j - 1]] < depth[dp[nxt][j - 1]]) { dp[i][j] = dp[i][j - 1]; } else { dp[i][j] = dp[nxt][j - 1]; } } }}int LCA(int u, int v){ int left = min(id[u], id[v]), right = max(id[u], id[v]); int k = (int)(log2(right - left + 1.0)); // 区间长度,注意用log2! int pos, nxt = right - (1 << k) + 1; // nxt 分界点 if (depth[dp[left][k]] < depth[dp[nxt][k]]) { pos = dp[left][k]; } else { pos = dp[nxt][k]; } return vis[pos];}int main(){ scanf("%d", &T); while (T--) { memset(head, -1, sizeof(head)); memset(in, 0, sizeof(in)); total = 0; int u, v; scanf("%d", &n); for (int i = 1; i <= n; ++i) { scanf("%d%d", &u, &v); if (i < n) { AddEdge(u, v); in[v]++; } } int root; for (int i = 1; i <= n; ++i) { if (in[i] == 0) { root = i; break; } } RMQ(root); printf("%d\n", LCA(u, v)); } return 0;}
- POJ 1330 Nearest Common Ancestors(LCA,在线处理三种方式)
- POJ 1330 Nearest Common Ancestors 在线LCA
- 【POJ】1330 Nearest Common Ancestors 在线LCA,倍增思想
- POJ 1330 Nearest Common Ancestors (在线LCA转RMQ)
- POJ - 1330 Nearest Common Ancestors(LCA在线查询)
- POJ 1330 Nearest Common Ancestors(在线倍增LCA)
- poj 1330 Nearest Common Ancestors lca rmq在线算法
- POJ 1330 Nearest Common Ancestors(LCA在线算法)
- POJ 1330 Nearest Common Ancestors(LCA 在线算法)
- POJ-1330 Nearest Common Ancestors【LCA】
- POJ 1330 Nearest Common Ancestors [LCA+RMQ]
- POJ 1330Nearest Common Ancestors LCA模板
- poj 1330 Nearest Common Ancestors(LCA)
- POJ 1330 Nearest Common Ancestors (LCA)
- poj 1330 Nearest Common Ancestors (LCA)
- poj 1330 Nearest Common Ancestors(LCA模板)
- POJ 1330 Nearest Common Ancestors LCA
- POJ 1330 Nearest Common Ancestors LCA
- 深入类加载器二----主动引用和被动引用
- CodeForces 703D Mishka and Interesting sum (树状数组处理异或和)
- 趣好玩开发日志 02-day
- const常量
- 入门算法之冒泡排序
- POJ 1330 Nearest Common Ancestors(LCA,在线处理三种方式)
- AndroidDeveloper Weekly NO.4
- Ubuntu16.04下载编译Android6.0源码以及我所踩的坑
- tomcat运行程序失败:更改端口号方法,Several ports (8005, 8080, 8009)
- Maven 安装ojdbc6.jar
- 深入类加载器----类加载器的分类和等级
- LintCode:复制带随机指针的链表
- DevOps linux 常用命令
- 深入类加载器----线程上下文类加载器