hdu2874 Connections between cities - LCA在线算法

来源:互联网 发布:淘宝店铺广告联盟 编辑:程序博客网 时间:2024/04/30 09:13
求任意两点之间的最短距离,本应该用最短路径算法。
但这题明确了图不含环,某些点之间可能没有边。

所以给出的图就可以转化为一片森林,对于每棵树,指定一个根节点root,dis[i]表示点i到root的距离,
任意两点i和j的最短距离 = dis[i] + dis[j] - 2 * dis[LCA(i, j)],
所以可以改用“并查集 + LCA”的方法

并查集用于判断给定的两个点是否连通。


查阅过网上很多人给出的算法都是LCA离线算法,如今就只给出LCA的在线算法。

#include<stdio.h>#include<string.h>#include<vector>#include<queue>#define maxn 10001using namespace std;typedef struct NODE{int v, len;NODE(int _v=0, int _len=0):v(_v), len(_len){}bool operator < (const struct NODE& rhs) const{ return len < rhs.len; }} node;vector<node> edge[maxn];int dis[maxn];int H[maxn], fa[maxn];//点的高度,父结点void dfs(int u, int h, int father){H[u] = h;fa[u] = father;for(int i=0; i<edge[u].size(); i++){node& e = edge[u][i];if(!fa[e.v]){dis[e.v] = dis[u] + e.len;dfs(e.v, h+1, u);}}}void swap(int& a, int& b){int t = a; a = b; b = t;}int LCA(int p, int q){if(H[p] < H[q])swap(p, q);//确保p比q深,即p的高度大于q的高度while(H[p] > H[q]) p = fa[p];//将p提升至与q同一高度if(p == q) return p;while(p != q) p = fa[p], q = fa[q];//p和q一起提升直到两者"相遇"return p;}int solve(int p, int q){int tmp = LCA(p, q);return dis[p] + dis[q] - 2 * dis[tmp];}int f[maxn];//并查集int find(int x){return f[x]==x ? x : f[x]=find(f[x]);}int main(){freopen("input.txt", "r", stdin);int n;//n个点int m;//m条边int c;//c次询问int a, b, k;//点a和点b间的距离是kwhile(scanf("%d %d %d", &n, &m, &c) != EOF){int i;for(i=1; i<=n; i++) edge[i].clear(), f[i] = i;while(m--){scanf("%d %d %d", &a, &b, &k);edge[a].push_back( node(b, k) );edge[b].push_back( node(a, k) );int x = find(a), y = find(b);if(x<y) f[y] = x; else f[x] = y;}memset(H, 0, sizeof(H));memset(fa, 0, sizeof(fa)); for(int j=1; j<=n; j++)if(f[j]==j){dis[j] = 0;dfs(j, 1, -1);//点j是根,高度为1,求出连通分量其它点的高度,父结点}int p, q;while(c--){scanf("%d %d", &p, &q);if(find(p) != find(q))//p和q不在同一个连通分量printf("Not connected\n");else{int ans = solve(p, q); printf("%d\n", ans);}}}return 0;}



0 0
原创粉丝点击