0%

蓝桥杯PREV09-大臣的旅费

题目链接

题目概述

求树的直径。

题目分析

对于树的直径,《算法导论》上有这么一句:

树中所有最短路径的最大值即为树的直径。

换句话说,不重复路径的最大值即为树的直径。有以下算法可快速求出树的直径:

先对任意一个结点做 BFS / DFS 求出最远的结点,然后以这个结点为起始结点再做 BFS / DFS 到达另一个最远结点。第一次到达的结点是这个图的直径的一端,第二次到达的则为另一端。

详细证明可见此

完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <bits/stdc++.h>
using namespace std;

const int MAXN=10005;
int maps[MAXN][MAXN];
bool vst[MAXN][MAXN];
vector<int> dis[MAXN];
int maxlen,n,maxi;
void dfs(int x, int len){
if(maxlen<len){
maxlen=len;
maxi=x;
}
for(int i=0; i<dis[x].size(); i++){
if(vst[x][dis[x][i]]||maps[x][dis[x][i]]==0)
continue;
vst[x][dis[x][i]]=vst[dis[x][i]][x]=1;
dfs(dis[x][i], len+maps[x][dis[x][i]]);
vst[x][dis[x][i]]=vst[dis[x][i]][x]=0;
}
}

int main(){
scanf("%d", &n);
int p,q,d;
for(int i=0; i<n-1; i++){
scanf("%d%d%d", &p, &q, &d);
maps[p][q]=maps[q][p]=d;
dis[p].push_back(q);
dis[q].push_back(p);
}

dfs(1,0);
dfs(maxi,0);
int ans=0;
for(int i=1; i<=maxlen; i++)
ans+=i+10;
printf("%d\n", ans);
return 0;
}

自我总结

原本是以每一个结点为起点,做 DFS ,然后挑出最长路径,果断超时。然后看到有关于“树的直径”以及其快速求解的算法,才得以解决,说明还是有很多没接触过的基础性知识。以及 DFS 写起来真方便(。