hdu 2874 Connections between cities LCA || dfs+并查集
2014-09-29 11:10
441 查看
题意:
给出一些树:有n(10000), m条边(10000), c(1000000)个询问,每个询问a b要求找到a到b的最短距离,如果ab不在同一棵树,输出-1.
题解:
此题就是找两个节点的最近公共祖先,则两者的距离就是a和b到根节点的距离之和 - 2倍公共祖先到根节点的距离。可用离线的LCA算法,其实就是dfs+并查集,下面分析一下离线的LCA, 我是看了原理后,自己敲出的代码。
LCA:
离线的LCA,其实就是说,只用一次dfs遍历所有的节点,就可以找出任意两个节点的距离,但是问题是,由于节点太多,无法保存任意两个节点的距离,所以在具体应用中,需要先保存询问,然后在dfs的过程中,只需要保存询问的节点的答案即可。LCA: 其实就是先序遍历这棵树,然后当访问完一个节点后,就把这个节点和他的父节点用并查集并到一起,那么当访问到要询问的节点U后,只需要判断询问边的另一个节点V是否被访问过了,如果被访问过了,则V的父节点就是两者的最近公共祖先。
细节:
在本题中,可能不止一颗树,所以在处理过程中,可以增加一个虚拟的0节点,作为所有节点的根节点,这样,如果访问节点的父节点是0节点,就代表这两个节点不属于同一棵树,则他们应该输出-1.
代码:
给出一些树:有n(10000), m条边(10000), c(1000000)个询问,每个询问a b要求找到a到b的最短距离,如果ab不在同一棵树,输出-1.
题解:
此题就是找两个节点的最近公共祖先,则两者的距离就是a和b到根节点的距离之和 - 2倍公共祖先到根节点的距离。可用离线的LCA算法,其实就是dfs+并查集,下面分析一下离线的LCA, 我是看了原理后,自己敲出的代码。
LCA:
离线的LCA,其实就是说,只用一次dfs遍历所有的节点,就可以找出任意两个节点的距离,但是问题是,由于节点太多,无法保存任意两个节点的距离,所以在具体应用中,需要先保存询问,然后在dfs的过程中,只需要保存询问的节点的答案即可。LCA: 其实就是先序遍历这棵树,然后当访问完一个节点后,就把这个节点和他的父节点用并查集并到一起,那么当访问到要询问的节点U后,只需要判断询问边的另一个节点V是否被访问过了,如果被访问过了,则V的父节点就是两者的最近公共祖先。
细节:
在本题中,可能不止一颗树,所以在处理过程中,可以增加一个虚拟的0节点,作为所有节点的根节点,这样,如果访问节点的父节点是0节点,就代表这两个节点不属于同一棵树,则他们应该输出-1.
代码:
#include <cstdio> #include <algorithm> #include <vector> #include <cstring> using namespace std; const int maxn = 1e4 + 10; int n, m, c, fa[maxn], ans[1000000+10], vis[maxn], dist[maxn]; struct Node{ int v, d; Node(int v = 0, int d = 0) : v(v), d(d){} }; vector<Node> G[maxn]; vector<Node> query[maxn]; int findSet(int x) { if (x != fa[x]) { fa[x] = findSet(fa[x]); } return fa[x]; } void init() { for (int i = 0; i <= n; i++) { fa[i] = i; dist[i] = 0; vis[i] = 0; G[i].clear(); query[i].clear(); } for (int i = 0; i < m; i++) { int u, v, d; scanf("%d%d%d", &u, &v, &d); G[u].push_back(Node(v, d)); G[v].push_back(Node(u, d)); int fu = findSet(u), fv = findSet(v); if (fu != fv) { fa[fu] = fv; } } for (int i = 1; i <= n; i++) { int fi = findSet(i); if (fa[fi] == i) { G[0].push_back(Node(i, 0)); } } for (int i = 0; i <= n; i++) { fa[i] = i; } for (int i = 0; i < c; i++) { int u, v; scanf("%d%d", &u, &v); ans[i] = -1; query[u].push_back(Node(v, i)); query[v].push_back(Node(u, i)); } } void print() { for (int i = 0; i < c; i++) { if (ans[i] != -1) { printf("%d\n", ans[i]); } else printf("Not connected\n"); } } void dfs(int u) { vis[u] = 1; for (int i = 0; i < query[u].size(); i++) { int fv = findSet(query[u][i].v); if (vis[query[u][i].v] && fa[fv] != 0) { ans[query[u][i].d] = dist[query[u][i].v] + dist[u] - 2*dist[fa[fv]]; } } for (int i = 0; i < G[u].size(); i++) { if (vis[G[u][i].v]) continue; dist[G[u][i].v] = dist[u] + G[u][i].d; dfs(G[u][i].v); int fv = findSet(G[u][i].v); int fu = findSet(u); fa[fv] = fa[fu]; } } int main() { // freopen("/Users/apple/Desktop/in.txt", "r", stdin); while (scanf("%d%d%d", &n, &m, &c) != EOF) { init(); dfs(0); print(); } return 0; }
相关文章推荐
- Connections between cities HDU - 2874(LCA)(RMQ)(dfs)(st算法)
- |hdu 2874|LCA|并查集|Connections between cities
- HDU 2874 Connections between cities (离线LCA)
- hdu 2874 Connections between cities (LCA转RMQ)
- 【HDU】2874 Connections between cities 离线LCA
- hdu-2874 Connections between cities(lca+tarjan+并查集)
- 【LCA转RMQ ST】 HDU 2874 Connections between cities
- hdu 2874 Connections between cities 最近公共祖先lca(离线算法/tarjan算法)
- HDU 2874 Connections between cities (LCA)
- hdu 2874 Connections between cities [LCA] (lca->rmq)
- HDU 2874 Connections between cities LCA
- hdu 2874 Connections between cities LCA
- hdu 2874 Connections between cities(LCA离线算法)
- HDU 2874 Connections between cities(LCA离线)
- hdu 2874 Connections between cities(LCA)
- HDU 2874 Connections between cities(LCA)
- hdu 2874 Connections between cities (LCA)
- hdoj 2874 Connections between cities 【并查集合并森林成一棵树 + LCA转RMQ】
- hdu 2874 Connections between cities(LCA)
- hdu 2874 Connections between cities(LCA)