-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathPT07Z.cs
171 lines (136 loc) · 5.54 KB
/
PT07Z.cs
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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
using System;
using System.Collections.Generic;
using System.Linq;
// https://www.spoj.com/problems/PT07Z/ #bfs #graph-theory #longest-path #proof #tree
// Finds the longest path in a tree.
public static class PT07Z
{
// See image for details: http://i.imgur.com/hWnw1N9.jpg.
public static int Solve(int nodeCount, int[,] edges)
{
if (nodeCount == 1)
return 0;
var graph = SimpleGraph.CreateFromOneBasedEdges(nodeCount, edges);
var firstVertex = graph.Vertices.First(v => v.Degree == 1);
var secondVertex = graph.FindFurthestVertex(firstVertex).Item1;
int longestPathLength = graph.FindFurthestVertex(secondVertex).Item2;
return longestPathLength;
}
}
// Undirected, unweighted graph with no loops or multiple edges. The graph's vertices are stored
// in an array, with the ID of a vertex (from 0 to vertexCount - 1) corresponding to its index.
public sealed class SimpleGraph
{
public SimpleGraph(int vertexCount)
{
var vertices = new Vertex[vertexCount];
for (int id = 0; id < vertexCount; ++id)
{
vertices[id] = new Vertex(this, id);
}
Vertices = vertices;
}
// For example, edges like (1, 2), (2, 3) => there's an edge between vertices 0 and 1 and 1 and 2.
public static SimpleGraph CreateFromOneBasedEdges(int vertexCount, int[,] edges)
{
var graph = new SimpleGraph(vertexCount);
for (int i = 0; i < edges.GetLength(0); ++i)
{
graph.AddEdge(edges[i, 0] - 1, edges[i, 1] - 1);
}
return graph;
}
public IReadOnlyList<Vertex> Vertices { get; }
public int VertexCount => Vertices.Count;
public void AddEdge(int firstVertexID, int secondVertexID)
=> AddEdge(Vertices[firstVertexID], Vertices[secondVertexID]);
public void AddEdge(Vertex firstVertex, Vertex secondVertex)
{
firstVertex.AddNeighbor(secondVertex);
secondVertex.AddNeighbor(firstVertex);
}
public bool HasEdge(int firstVertexID, int secondVertexID)
=> HasEdge(Vertices[firstVertexID], Vertices[secondVertexID]);
public bool HasEdge(Vertex firstVertex, Vertex secondVertex)
=> firstVertex.HasNeighbor(secondVertex);
public Tuple<Vertex, int> FindFurthestVertex(int startVertexID)
=> FindFurthestVertex(Vertices[startVertexID]);
// This finds a furthest vertex from the start vertex, that is, a vertex whose (shortest) path
// to the start is the longest, and returns that vertex and its distance (path length) from the start.
public Tuple<Vertex, int> FindFurthestVertex(Vertex startVertex)
{
bool[] discoveredVertexIDs = new bool[VertexCount];
var verticesToVisit = new Queue<Vertex>();
discoveredVertexIDs[startVertex.ID] = true;
verticesToVisit.Enqueue(startVertex);
Vertex furthestVertex = null;
int furthestDistance = -1;
// We visit vertices in waves, where all vertices in the same wave are the same distance
// from the start vertex, which BFS makes convenient. This allows us to avoid storing
// distances to the start vertex at the level of individual vertices.
while (verticesToVisit.Count > 0)
{
// We don't care which furthest vertex we get from this wave, so we just choose the first.
furthestVertex = verticesToVisit.Peek();
++furthestDistance;
int waveSize = verticesToVisit.Count;
for (int i = 0; i < waveSize; ++i)
{
var vertex = verticesToVisit.Dequeue();
foreach (var neighbor in vertex.Neighbors)
{
if (!discoveredVertexIDs[neighbor.ID])
{
discoveredVertexIDs[neighbor.ID] = true;
verticesToVisit.Enqueue(neighbor);
}
}
}
}
return Tuple.Create(furthestVertex, furthestDistance);
}
public sealed class Vertex : IEquatable<Vertex>
{
private readonly SimpleGraph _graph;
private readonly HashSet<Vertex> _neighbors = new HashSet<Vertex>();
internal Vertex(SimpleGraph graph, int ID)
{
_graph = graph;
this.ID = ID;
}
public int ID { get; }
public IReadOnlyCollection<Vertex> Neighbors => _neighbors;
public int Degree => _neighbors.Count;
internal void AddNeighbor(int neighborID)
=> _neighbors.Add(_graph.Vertices[neighborID]);
internal void AddNeighbor(Vertex neighbor)
=> _neighbors.Add(neighbor);
public bool HasNeighbor(int neighborID)
=> _neighbors.Contains(_graph.Vertices[neighborID]);
public bool HasNeighbor(Vertex neighbor)
=> _neighbors.Contains(neighbor);
public override bool Equals(object obj)
=> (obj as Vertex)?.ID == ID;
public bool Equals(Vertex other)
=> other.ID == ID;
public override int GetHashCode()
=> ID;
}
}
public static class Program
{
private static void Main()
{
int nodeCount = int.Parse(Console.ReadLine());
int edgeCount = nodeCount - 1;
int[,] edges = new int[edgeCount, 2];
for (int i = 0; i < edgeCount; ++i)
{
int[] edge = Array.ConvertAll(Console.ReadLine().Split(), int.Parse);
edges[i, 0] = edge[0];
edges[i, 1] = edge[1];
}
Console.WriteLine(
PT07Z.Solve(nodeCount, edges));
}
}