Определить диаметр не взвешенного неориентированного графа обходом в ширину(волновым обходом)
Доброй/ый утро, день, вечер или ночь, дорогие программисты! Встретился с проблемой, ответ на который могу сделать на бумаге, но программно объяснить , увы, уже который день не выходит.
Мне требуется посчитать диаметр(самый длинный путь из одной точки в другую) не взвешенного, неориентированного графа обходом в ширину или иначе волновым обходом , а также вывести его диаметральные цепи (на самом деле задание требует только 1 цепь, но пара обратных сойдёт для начала).
Во-первых, объясню свою реализацию графа (может проблема в ней и что-то действительно стоит изменить?), используя язык программирования C#.
Собственно сам граф, с которым я работаю:
Vertex(вершины):
//имя вершины
private string name;
//Список рёбер графа
private List<GraphEdge> edges;
public string Name { get=>name; }
public List<GraphEdge> Edges { get=>edges; }
public GraphVertex(string vertexName)
{
name = vertexName;
edges = new List<GraphEdge>();
}
public void AddEdge(GraphEdge edge)
{
edges.Add(edge);
}
Edges(Рёбра):
public class GraphEdge
{
//Список соединённых вершин
private GraphVertex[] connectedVertex = new GraphVertex[2];
public GraphVertex[] ConnectedVertex { get => connectedVertex; }
public GraphEdge(GraphVertex connectedVertex1, GraphVertex connectedVertex2)
{
connectedVertex[0] = connectedVertex1;
connectedVertex[1] = connectedVertex2;
}
}
Собственно сам граф:
public class Graph
{
//Список всех вершин
private List<GraphVertex> vertices;
public List<GraphVertex> Vertices { get => vertices; }
public List<GraphEdge> edges;
public Graph()
{
vertices = new List<GraphVertex>();
edges = new List<GraphEdge>();
}
//Добавление вершин
public void AddVertices(params GraphVertex[] vertexes)
{
foreach (var vertex in vertexes)
{
vertices.Add(vertex);
}
}
//добавление Рёбра по именам двух вершин
public void AddEdge(string firstVertexName, string secondVertexName, GraphEdge edge)
{
GraphVertex firstVertex = FindVertex(firstVertexName);
GraphVertex secondVertex = FindVertex(secondVertexName);
if (firstVertex != null && secondVertex != null)
{
firstVertex.AddEdge(edge);
secondVertex.AddEdge(edge);
CompleteEdges();
}
}
//Поиск вершины по имени
public GraphVertex FindVertex(string vertexName)
{
foreach (GraphVertex v in vertices)
{
if (v.Name.Equals(vertexName)) return v;
}
return null;
}
//найти смежных
public List<GraphVertex> GetAdjacentVertexes(GraphVertex vertex)
{
List<GraphVertex> result = new List<GraphVertex>
{
vertex
};
foreach (GraphEdge edge in vertex.Edges)
{
foreach (GraphVertex vert in edge.ConnectedVertex)
{
if (!(result.Contains(vert))) result.Add(vert);
}
}
return result;
}
//Вернуть "размер" графа
public int GetSize()
{
return vertices.Count+1;
}
//метод для заполнения List рёбер
private void CompleteEdges()
{
foreach (var v in vertices)
{
foreach (var e in v.Edges)
{
if (!(edges.Contains(e))) edges.Add(e);
}
}
}
}
Теперь к самой реализации метода обхода в глубину, в данном случае в правильном порядке выводятся обойдённые вершины, однако, как "привязать" только "нужные" рёбра(или же вершины, если хотя бы что-то из этого выйдет, то там уже можно будет спокойно вывести всё на консоль), а также посчитать диаметр мне пока в голову не приходит, итак , дамы и господа, мой BFS:
public static HashSet<GraphVertex> BFS(Graph gr, GraphVertex startPoint)
{
var visited = new HashSet<GraphVertex>();
Queue<GraphVertex> queue = new Queue<GraphVertex>();
queue.Enqueue(startPoint);
while (queue.Count > 0)
{
var vertex = queue.Dequeue();
if (visited.Contains(vertex)) continue;
visited.Add(vertex);
foreach(var neighbor in gr.GetAdjacentVertexes(vertex))
{
if (!visited.Contains(neighbor))
{
diametr++;
queue.Enqueue(neighbor);
}
}
}
return visited;
}
Заранее извиняюсь за , вероятнее всего, свой ужасный код, уверен у вас есть варианты куда лучше, но на данный момент моих усилий хватило только на данную реализацию, пожалуйста, предложите свои идеи и варианты.
Ответы (1 шт):
Чтобы посчитать диаметр графа с помощью BFS, выполняют V поисков BFS (из каждой вершины) и определяют наибольшее найденное расстояние среди всех поисков.
Для построения самой длинной цепи нужно завести параллельные структуры данных, и на каждом шаге записывать в неё предшественника и расстояние от начальной вершины
if (!visited.Contains(neighbor))
{
//здесь что-то вроде
pred[neighbor] = vertex;
dist[neighbor] = dist[vertex] + 1;
if (dist[neighbor] > maxdist) {
maxdist = dist[neighbor];
farthest = neigbor;
}
queue.Enqueue(neighbor);
}
После каждого поиска, если maxdist улучшено, восстанавливаем цепь по pred и запоминаем её