题目描述:
There are n houses in the village and some bidirectional roads connecting them. Every day peole always like to ask like this “How far is it if I want to go from house A to house B”? Usually it hard to answer. But luckily int this village the answer is always unique, since the roads are built in the way that there is a unique simple path(“simple” means you can’t visit a place twice) between every two houses. Yout task is to answer all these curious people.
输出格式:
For each test case,output m lines. Each line represents the answer of the query. Output a bland line after each test case.
输入数据:
2
3 2
1 2 10
3 1 15
1 2
2 3
2 2
1 2 100
1 2
2 1
输出数据:
10
25
100
100
解析
- 题目大意:
城镇之间互相有道路(双向边),且只存在n-1条边,保证相互可达,求两点
之间的距离。
- 思路:
解法一: vector邻接表 + dfs
算法一:vector邻接表 + dfs
#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
#define min(x,y) (x<y?x:y)
const int N = 40005, inf = 0x3f3f3f3f;
struct Edge{
int from, to, weight;
Edge(){}
Edge(int from, int to, int weight) {
this->from = from;
this->to = to;
this->weight = weight;
}
};
vector<Edge> Map[N];
int ans, vis[N];
void dfs(int x,int y, int sum) ;
int main() {
int t;
cin >> t;
while (t--) {
int n, m;
cin >> n >> m;
int from, to, len;
for (int i = 0; i < n-1; i++) {
cin >> from >> to >> len;
Map[from].push_back(Edge(from,to,len));
Map[to].push_back(Edge(to,from,len));
}
int x, y;
for (int i = 0; i < m; i++) {
cin >> x >> y;
ans = inf;
memset(vis,0,sizeof(vis));
dfs(x,y,0);
cout << ans << endl;
}
for (int i = 1; i <= n; i++) Map[i].clear();
}
}
void dfs(int x,int y, int sum) {
if (x == y) {
ans = min(ans,sum);
}
if (sum > ans) return ;
for (int i = 0; i < Map[x].size(); i++) {
Edge temp = Map[x][i];
if (vis[temp.to] == 0) {
vis[temp.to] = 1;
dfs(temp.to,y,sum+temp.weight);
vis[temp.to] = 0;
}
}
}
解法二: 无向图(不存在环 即只有n-1条边) 所以可以将该图看作一棵树
转化为LCA裸问题,只需要再一边寻找最近公共祖先的同时,跟
新当前点到根节点的距离dist即可,那么节点u,v之间的距离为
dist[u]+dist[v]-2*dist[lca(u,v)];
//算法二:LCA 最近公共祖先算法 -- 无向图(不存在环 即只有n-1条边)的多组数据的最近公共祖先
#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
const int N = 40005, M = 205;
struct Edge {
int from, to, weight;
Edge(){}
Edge(int from, int to, int weight) {
this->from = from;
this->to = to;
this->weight = weight;
}
};
vector<Edge> Map[N];
vector<Edge> Query[N];
int dis[N], f[N], vis[N];
int result[M];
void Targin(int root) ;
int main() {
int t;
cin >> t;
while (t--) {
int n, m;
cin >> n >> m;
int from, to, len;
for (int i = 0; i < n-1; i++) {
f[i+1] = i+1;
cin >> from >> to >> len;
Map[from].push_back(Edge(from,to,len));
Map[to].push_back(Edge(to,from,len));
}
for (int i = 0; i < m; i++) {
cin >> from >> to;
Query[from].push_back(Edge(from,to,i));
Query[to].push_back(Edge(to,from,i));
}
// memset(dis,0,sizeof(dis));
dis[1] = 0;
memset(vis,0,sizeof(vis));
Targin(1);
for (int i = 0; i < m; i++) {
cout << result[i] << endl;
}
for (int i = 1; i <= n; i++) {
Query[i].clear();
Map[i].clear();
}
}
}
int GetFather(int x) {
int v = x;
while (v != f[v]) {
v = f[v];
}
int i = x, j;
while(i != v) {
j = f[i];
f[i] = v;
i = j;
}
return v;
}
void Union(int x,int y) {
int fx = GetFather(x), fy = GetFather(y);
if (fx != fy) {
f[fy] = fx;
}
}
void Targin(int root) {
vis[root] = 1;
for (int i = 0; i < Map[root].size(); i++) {
Edge temp = Map[root][i];
if (vis[temp.to] == 0) { // 这里是无向图 双向边 如果不用vis 数组记录 则会无限循环
// cout << root << "-" << temp.to << "-" << temp.weight << endl;
dis[temp.to] = dis[root] + temp.weight;
Targin(temp.to);
Union(root,temp.to);
}
}
for (int i = 0; i < Query[root].size(); i++) {
Edge temp = Query[root][i];
// cout << root << "--" << temp.to << endl;
if (vis[temp.to] == 1) {
int LCA = GetFather(temp.to);
// cout << LCA << "--" << dis[temp.to] << "--" << dis[root] << endl;
result[temp.weight] = dis[temp.to] + dis[root] - 2*dis[LCA];
}
}
}