简体   繁体   English

如何获得具有已知边的抽象多边形的顶点

[英]How to get the vertices of an abstract polygon with known edges

This is a restatement of a question that has now been deleted. 重述现已删除的问题。 I think it is an interesting question. 我认为这是一个有趣的问题。 The input of the problem is an array of two-element tuples, each one representing an abstract edge that connects two abstract vertices. 问题的输入是一个由两个元素组成的元组的数组,每个元组代表一个连接两个抽象顶点的抽象边。 The desired output is an array of connected vertices. 所需的输出是一组连接的顶点。 A vertex can be of any type, not necessarily a point in space, hence the "abstract" designation. 顶点可以是任何类型,不一定是空间点,因此是“抽象”名称。 The array is not expected to be ordered in any way. 不应以任何方式订购该阵列。 Actually the types are not even comparable. 实际上,这些类型甚至都不具有可比性。 We are only allowed to compare them for equality. 我们只允许比较它们是否相等。

Samples of input and output: 输入和输出样本:

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.");

Method signature: 方法签名:

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

class EqualityComparerExtensions that will return a value indicating if two edges are neighbors. 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);
    }
}

Then the algorithm would be: 那么算法将是:

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();
}

You trying to find connected components of an undirected graph. 您试图找到无向图的连接组件。 Strictly speaking, not connected components in general, but one component special case. 严格来说,不是一般连接的组件,而是一种特殊情况的组件。

You can find more about them in Wikipedia page and/or take a look at an example implementation in C# 您可以在Wikipedia页面上找到有关它们的更多信息,和/或查看C#中的示例实现。

Here is my solution. 这是我的解决方案。

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();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM