[英]How to get the vertices of an abstract polygon with known edges
重述了現已刪除的問題。 我認為這是一個有趣的問題。 問題的輸入是一個由兩個元素組成的元組的數組,每個元組代表一個連接兩個抽象頂點的抽象邊。 所需的輸出是一組連接的頂點。 頂點可以是任何類型,不一定是空間點,因此是“抽象”名稱。 不應以任何方式訂購該陣列。 實際上,這些類型甚至都不具有可比性。 我們只允許比較它們是否相等。
輸入和輸出樣本:
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);
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();
}
您試圖找到無向圖的連接組件。 嚴格來說,不是一般連接的組件,而是一種特殊情況的組件。
您可以在Wikipedia頁面上找到有關它們的更多信息,和/或查看C#中的示例實現。
這是我的解決方案。
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.