直径
2ノード間距離のうち最大のものを,そのグラフの直径という.ここでいう距離は,辺の重みは考慮しない.
木の直径は,2回のDFSで求めることができる.具体的には,任意のノードについて,最も遠いノードを求め,そのノードからまた最も遠いノードを求めると,後者の距離が木の直径である.以下に証明を示す.
証明
任意に選択したノードrから最も遠いノードxは直径の端点にならないと仮定する.直径(複数ありうる)の端点の集合をEとする.r->xパスが直径と最初に交わる点が存在すればそれをhとする.
- hが存在する時
r->h->xとなるパスが存在する.この時,hは直径上にあるので,hから最も遠いノードはEに属するノードである.ここで,rから最も遠いノードはxなのでxはEに属する.これはxが直径の端点にならないことに⽭盾する.
- hが存在しない時
以下の式から,xを端点とする直径を構成することができるため,xが直径の端点にならないことに⽭盾する.
dist(r,x)≥dist(r,h)+maxu∈E(dist(h,u))
よってdist(h,x)≥+maxu∈E(dist(h,u))
以上から,背理法より,任意に選択したノードrから最も遠いノードxは直径の端点になる.したがって,任意のノードについて,最も遠いノードを求め,そのノードのから最も遠いノードまでの距離が直径となる.
コード
pair<int, int> dfs(int node, int parent, vector<vector<int>> &g) {
pair<int, int> ret = {0, node};
for (int &e: g[node]) {
if (e == parent) continue;
pair<int, int> tmp = dfs(e, node, g);
tmp.first++;
chmax(ret, tmp);
}
return move(ret);
}
int diameter(vector<vector<int>> &g) {
pair<int, int> d = dfs(0, -1, g);
d = dfs(d.second, -1, g);
return d.first;
}