Определить диаметр не взвешенного неориентированного графа обходом в ширину(волновым обходом)

Доброй/ый утро, день, вечер или ночь, дорогие программисты! Встретился с проблемой, ответ на который могу сделать на бумаге, но программно объяснить , увы, уже который день не выходит.

Мне требуется посчитать диаметр(самый длинный путь из одной точки в другую) не взвешенного, неориентированного графа обходом в ширину или иначе волновым обходом , а также вывести его диаметральные цепи (на самом деле задание требует только 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 шт):

Автор решения: MBo

Чтобы посчитать диаметр графа с помощью 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 и запоминаем её

→ Ссылка