传送门:http://abc070.contest.atcoder.jp/tasks/abc070_d
本题是一个图论问题——树(Tree)。
有一棵结点数目为n的无向树。第i条边连接结点ai与bi,权值为ci。给出q次查询,以及一个整数k(1≤k≤n),第j次查询给出两个整数xj,yj(1≤xj,yj≤n),求解结点xj和yj通过结点k的最短路径长度。
树上的路径问题,可以通过DFS解决。以下代码片段计算结点间的路径长度dis。
void dfs(int v) { vis[v] = true; for (int i = 0; i < adj[v].size(); i++) { int u = adj[v][i].v; int w = adj[v][i].w; if (!vis[u]) { dis[u] = dis[v] + w; dfs(u); } } }
结点x和y通过结点k的最短路径可以分成两部分:结点k到x的最短路径和结点k到y的最短路径。如此,通过一个简单的DFS,求解结点k到i(1≤i≤n)的路径长度dis[i]。则查询的返回值为dis[x]+dis[y]。参考程序如下:
#include <bits/stdc++.h> using namespace std; #define MAX_N 100001 vector<pair<int, int> > adj[MAX_N]; int64_t dis[MAX_N]; bool vis[MAX_N]; void dfs(int v) { vis[v] = true; for (int i = 0; i < adj[v].size(); i++) { int u = adj[v][i].first; int w = adj[v][i].second; if (!vis[u]) { dis[u] = dis[v] + w; dfs(u); } } } int main(void) { int n, k, q; scanf("%d", &n); for (int i = 1; i < n; i++) { int a, b, c; scanf("%d%d%d", &a, &b, &c); adj[a].push_back(make_pair(b, c)); adj[b].push_back(make_pair(a, c)); } scanf("%d%d", &q, &k); dfs(k); while (q--) { int x, y; scanf("%d%d", &x, &y); printf("%lld ", dis[x] + dis[y]); } return 0; }