您的位置:首页 > 其它

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.

代码:

#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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: