【问题标题】:How to get the vertices of an abstract polygon with known edges如何获取具有已知边的抽象多边形的顶点
【发布时间】:2019-11-25 00:46:36
【问题描述】:

这是对a question 的重述,现已被删除。我认为这是一个有趣的问题。问题的输入是一个二元元组数组,每个元组代表一条连接两个抽象顶点的抽象边。所需的输出是连接顶点的数组。顶点可以是任何类型,不一定是空间中的点,因此是“抽象”名称。预计不会以任何方式对该数组进行排序。实际上,这些类型甚至没有可比性。我们只能比较它们是否相等。

输入输出示例:

var input = new[] { ('a', 'b'), ('c', 'b'), ('a', 'c') };
var output = new[] { 'a', 'b', 'c' };

var input = new[] { ("a", "b"), ("a", "b") };
var output = new[] { "a", "b" };

var input = new[] { (true, true) };
var output = new[] { true };

var input = new[] { (1, 2), (4, 3), (3, 2), (1, 4) };
var output = new[] { 1, 2, 3, 4 };

var input = new[] { (1, 2), (2, 3), (3, 4) };
var output = new InvalidDataException(
    "Vertices [1, 4] are not connected with exactly 2 other vertices.");

var input = new[] { (1, 2), (2, 1), (3, 4), (4, 3) };
var output = new InvalidDataException(
    "Vertices [3, 4] are not connected with the rest of the graph.");

方法签名:

public static T[] GetVerticesFromEdges<T>((T, T)[] edges,
    IEqualityComparer<T> comparer);

【问题讨论】:

    标签: c# .net algorithm graph


    【解决方案1】:

    EqualityComparerExtensions 类将返回一个值,指示两条边是否为邻居。

    static class EqualityComparerExtensions
    {
        internal static bool Neighbours<T>(this IEqualityComparer<T> comparer, 
            Tuple<T, T> a, Tuple<T, T> b)
        {
            return comparer.Equals(a.Item1, b.Item1) 
                || comparer.Equals(a.Item1, b.Item2)
                || comparer.Equals(a.Item2, b.Item1) 
                || comparer.Equals(a.Item2, b.Item2);
        }
    }
    

    那么算法将是:

    public static T[] GetVerticesFromEdges<T>(Tuple<T, T>[] edges, 
        IEqualityComparer<T> comparer)
    {
        var array = edges.Clone() as Tuple<T, T>[];
        var last = array.Length - 1;
        for (int i = 0; i < last; i++)
        {
            var c = 0;
            for (int j = i + 1; j < array.Length; j++)
            {
                if (comparer.Neighbours(array[i], array[j]))
                {
                    var t = array[i + 1];
                    array[i + 1] = array[j];
                    array[j] = t;
                    c++;
                }
            }
            if (c > 2 || c == 0)
            {
                throw new ArgumentException($"{nameof(edges)} is not a Polygon!");
            }
        }
        if (!comparer.Neighbours(array[last], array[0]))
        {
            throw new ArgumentException($"{nameof(edges)} is not a Polygon!");
        }
        for (int i = 0, j = 1; j < array.Length; i++, j++)
        {
            if (!comparer.Equals(array[i].Item2, array[j].Item1))
            {
                if (comparer.Equals(array[i].Item2, array[j].Item2))
                {
                    array[j] = Tuple.Create(array[j].Item2, array[j].Item1);
                }
                else
                {
                    array[i] = Tuple.Create(array[i].Item2, array[i].Item1);
                }
            }
        }
        if (!comparer.Equals(array[last].Item2, array[0].Item1))
        {
            throw new ArgumentException($"{nameof(edges)} is not a Polygon!");
        }
        return array.Select(a => a.Item1).ToArray();
    }
    

    【讨论】:

    • 此输入失败:(1, 3), (1, 2), (3, 2)。返回:1, 2, 2!
    • 现在失败了:(1, 2), (3, 1) 返回:2, 3!
    • 又添加了一个if,立即查看。
    • 现在它通过了我的测试!
    【解决方案2】:

    您试图找到无向图的连通分量。严格来说,不是一般的连接组件,而是一个组件的特例。

    您可以在 Wikipedia page 中找到有关它们的更多信息和/或查看示例 implementation in C#

    【讨论】:

      【解决方案3】:

      这是我的解决方案。

      public static T[] GetVerticesFromEdges<T>((T, T)[] edges,
          IEqualityComparer<T> comparer)
      {
          if (edges.Length == 0) return new T[0];
          var vertices = new Dictionary<T, List<T>>(comparer);
      
          void AddVertex(T vertex, T connectedVertex)
          {
              if (!vertices.TryGetValue(vertex, out var connectedVertices))
              {
                  connectedVertices = new List<T>();
                  vertices[vertex] = connectedVertices;
              }
              connectedVertices.Add(connectedVertex);
          }
      
          foreach (var edge in edges)
          {
              AddVertex(edge.Item1, edge.Item2);
              AddVertex(edge.Item2, edge.Item1);
          }
          var invalid = vertices.Where(e => e.Value.Count != 2).Select(e => e.Key);
          if (invalid.Any())
          {
              throw new InvalidDataException(
                  "Vertices [" + String.Join(", ", invalid) +
                  "] are not connected with exactly 2 other vertices.");
          }
      
          var output = new List<T>();
          var currentVertex = vertices.Keys.First();
          while (true)
          {
              output.Add(currentVertex);
              var connectedVertices = vertices[currentVertex];
              vertices.Remove(currentVertex);
              if (vertices.ContainsKey(connectedVertices[0]))
              {
                  currentVertex = connectedVertices[0];
              }
              else if (vertices.ContainsKey(connectedVertices[1]))
              {
                  currentVertex = connectedVertices[1];
              }
              else
              {
                  break;
              }
          }
          if (vertices.Count > 0)
          {
              throw new InvalidDataException(
                  "Vertices [" + String.Join(", ", vertices.Keys) +
                  "] are not connected with the rest of the graph.");
          }
          return output.ToArray();
      }
      

      【讨论】:

        猜你喜欢
        • 2020-02-11
        • 1970-01-01
        • 2017-07-19
        • 2013-05-26
        • 1970-01-01
        • 2021-12-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多