โจทย์: กำหนด Edge List ที่แต่ละรายการ (u, v) แสดงว่า u เป็นพาเรนต์ของ v หา ความยาวเส้นทางที่ยาวที่สุด (Diameter) ในต้นไม้ โดยนิยามความยาว = 1 + จำนวนโหนดในเส้นทาง
ตัวอย่าง
Edges: [(1, 2), (1, 3), (1, 4), (4, 5), (5, 7), (1, 6), (4, 8)]
โครงสร้างต้นไม้:
1
/ | \
2 3 4
/ \
5 8
/
7
เส้นทางยาวสุด: [1, 4, 5, 7] มี 4 โหนด → ความยาว = 1 + 4 = 5
อัลกอริทึม: Two BFS (Double BFS) หา Diameter
หลักการ: เริ่ม BFS จากโหนดไหนก็ได้ หาจุดไกลสุด f แล้ว BFS จาก f อีกครั้ง ระยะทางไกลสุดครั้งที่ 2 = Diameter
ขั้นตอนการทำงาน
- สร้าง Adjacency List
gจาก Edge List (Undirected) - ฟังก์ชัน
bfs(o):d[o] = 1(ระยะจากตัวเอง = 1)- BFS ปกติ อัปเดต
d[y] = d[x] + 1 - ติดตามโหนดไกลสุด
f - คืนค่า
f
- จากโหนดไหนก็ได้ใน
g:f = bfs(o)(หาจุดไกลสุดจากจุดเริ่มต้น)- รีเซ็ต
d = {} - คืนค่า
d[bfs(f)](ระยะทางจากจุดไกลสุดไปจุดไกลสุดอีกฝั่ง)
โค้ด Python
def solve(edges):
# สร้าง Adjacency List (Undirected)
g = {}
for u, v in edges:
if u not in g:
g[u] = []
g[u].append(v)
if v not in g:
g[v] = []
g[v].append(u)
d = {}
def bfs(o):
d[o] = 1
f = o
q = [o]
for x in q:
for y in g[x]:
if y not in d:
d[y] = d[x] + 1
if d[y] > d[f]:
f = y
q.append(y)
return f
# Two BFS trick
for o in g:
f = bfs(o)
d = {}
return d[bfs(f)]
return 0
# ทดสอบ
edges = [(1, 2), (1, 3), (1, 4), (4, 5), (5, 7), (1, 6), (4, 8)]
print(solve(edges)) # Output: 5
ความซับซ้อน
- Time Complexity: O(N) โดย N = จำนวนโหนด (BFS 2 รอบ)
- Space Complexity: O(N) สำหรับ Adjacency List และ Distance Map
หมายเหตุเกี่ยวกับโค้ดต้นฉบับ
โค้ดต้นฉบับมี for o in g: แต่มี return อยู่ในลูป ทำให้รันแค่รอบเดียว (ซึ่งก็เพียงพอแล้ว เพราะ BFS ครั้งแรกจากโหนดไหนก็ได้จะหาจุดปลายเส้นทางยาวสุดได้) แต่การเขียนที่ชัดเจนกว่าควรแยกนอกลูป:
def solve(edges):
g = {}
for u, v in edges:
g.setdefault(u, []).append(v)
g.setdefault(v, []).append(u)
def bfs(start):
dist = {start: 1}
q = [start]
farthest = start
for x in q:
for y in g[x]:
if y not in dist:
dist[y] = dist[x] + 1
if dist[y] > dist[farthest]:
farthest = y
q.append(y)
return farthest, dist
# เริ่มจากโหนดแรก
any_node = next(iter(g))
farthest1, _ = bfs(any_node)
farthest2, dist2 = bfs(farthest1)
return dist2[farthest2]
# ทดสอบ
edges = [(1, 2), (1, 3), (1, 4), (4, 5), (5, 7), (1, 6), (4, 8)]
print(solve(edges)) # 5
การทดสอบเพิ่มเติม
# เส้นตรง (Line)
print(solve([(1,2), (2,3), (3,4), (4,5)])) # 5
# ดาว (Star)
print(solve([(1,2), (1,3), (1,4), (1,5)])) # 3 (1-2-1-3 path length 3 nodes = 3)
# Binary Tree
edges = [(1,2), (1,3), (2,4), (2,5), (3,6), (3,7)]
print(solve(edges)) # 5 (4-2-1-3-6 or similar)