HDU2874(Connections between cities)

Connections between cities

题目传送门
Problem Description
After World War X, a lot of cities have been seriously damaged, and we need to rebuild those cities. However, some materials needed can only be produced in certain places. So we need to transport these materials from city to city. For most of roads had been totally destroyed during the war, there might be no path between two cities, no circle exists as well.
Now, your task comes. After giving you the condition of the roads, we want to know if there exists a path between any two cities. If the answer is yes, output the shortest path between them.

Input
Input consists of multiple problem instances.For each instance, first line contains three integers n, m and c, 2<=n<=10000, 0<=m<10000, 1<=c<=1000000. n represents the number of cities numbered from 1 to n. Following m lines, each line has three integers i, j and k, represent a road between city i and city j, with length k. Last c lines, two integers i, j each line, indicates a query of city i and city j.

Output
For each problem instance, one line for each query. If no path between two cities, output “Not connected”, otherwise output the length of the shortest path between them.

Sample Input
5 3 2
1 3 2
2 4 3
5 2 3
1 4
4 5

Sample Output
Not connected
6

题意

第一次世界大战后,许多城市遭到严重破坏,我们需要重建这些城市。但是,某些材料只能在某些地方生产。所以我们需要将这些材料从一个城市运到另一个城市。由于战争期间大部分道路已被完全摧毁,两个城市之间可能没有路径,也没有环存在。 现在,你的任务来了。在告诉您道路状况后,我们想知道任何两个城市之间是否存在路径。如果答案是肯定的,则输出它们之间的最短路径。

思路

倍增ST + LCA + 并查集

  1. 先预处理这张图,对于联通的点用并查集维护然后去dfs得到一颗深度优先生成树
  2. 对于查询的两个点,如果不在同一颗树根下那么不连通直接用并查集查询
  3. 对于查询的两个点做LCA。这两点之间的距离可以转化为这两个点到根节点的距离 减掉 2倍的LCA到根节点的距离。
#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 10005;
const int maxd = 19;
struct edge{
	int to;
	int w;
	int next;
}e[maxn<<1];
int f[maxn][20];
int head[maxn];
int s[maxn];			
bool vis[maxn];
int dist[maxn];
int dep[maxn];
int tot;
void clear_set()
{
	tot = 0;
	memset(head,-1,sizeof(head));
	memset(dist,0,sizeof(dist));
	memset(vis,false,sizeof(vis));
	memset(dep,0,sizeof(dep));
	memset(f,0,sizeof(f));
	for(int i = 0;i < maxn;i++)		s[i] = i;
}
void addedge(int x,int y,int z)
{
	e[tot].to = y;
	e[tot].w = z;
	e[tot].next = head[x];
	head[x] = tot++;
}
int find_set(int x)
{
	if(x != s[x]){
		s[x] = find_set(s[x]);
	}
	return s[x];
}
void dfs(int x,int fx)
{
	dep[x] = dep[fx] + 1;vis[x] = true;
	f[x][0] = fx;
	for(int i = 1;i <= maxd;i++){
		f[x][i] = f[f[x][i-1]][i-1];
	}
	for(int i = head[x];~i;i = e[i].next){
		int y = e[i].to;
		if(y != fx){
			dist[y] = dist[x] + e[i].w;
			dfs(y,x);	
		}
	}
}
int LCA(int x,int y)
{
	if(dep[x] < dep[y])		swap(x,y);
	int d = dep[x] - dep[y];
	for(int i = 0;i <= maxd;i++){
		if(((1<<i)&d)){
			x = f[x][i];
		}
	}
	if(x == y)		return x;
	for(int i = maxd;i >= 0;i--){
		if(f[x][i] != f[y][i]){
			x = f[x][i];
			y = f[y][i];
		}
	}
	return f[x][0];
}
int main()
{
	int n,m,q;
	while(~scanf("%d%d%d",&n,&m,&q)){
		clear_set();
		int x,y,z;
		for(int i = 0;i < m;i++){
			scanf("%d%d%d",&x,&y,&z);
			addedge(x,y,z);addedge(y,x,z);
			int fx = find_set(x);
			int fy = find_set(y);
			if(fx != fy)	s[fx] = fy;			//维护两个点的连通性
		}
		for(int i = 1;i <= n;i++){
			if(!vis[i]){
				dfs(i,0);
			}
		}
		while(q--){
			scanf("%d%d",&x,&y);
			int fx = find_set(x);
			int fy = find_set(y);
			if(fx != fy){
				printf("Not connected\n");
				continue;
			}
			int t = LCA(x,y);
			int ans = dist[x] + dist[y] - 2*dist[t];
			printf("%d\n",ans);
		}
	}
	return 0;
}

愿你走出半生,归来仍是少年~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值