private static void CollapseEdge(KargerGraph graph, KargerGraphEdge edge) { // Remove the edge graph.Edges.Remove(edge); edge.FromVertex.Edges.Remove(edge); edge.ToVertex.Edges.Remove(edge); // Merge the two vertices of the edge edge.FromVertex.ContainedPolygons.AddRange(edge.ToVertex.ContainedPolygons); graph.Vertices.Remove(edge.ToVertex); foreach (KargerGraphEdge toEdge in edge.ToVertex.Edges) { if(toEdge != edge) { edge.FromVertex.Edges.Add(toEdge); if (toEdge.FromVertex == edge.ToVertex) { toEdge.FromVertex = edge.FromVertex; } else if (toEdge.ToVertex == edge.ToVertex) { toEdge.ToVertex = edge.FromVertex; } } } // Remove self-loops List<KargerGraphEdge> edgesToRemove = new List<KargerGraphEdge>(); foreach(KargerGraphEdge newEdge in edge.FromVertex.Edges) { if(newEdge.FromVertex == newEdge.ToVertex) { edgesToRemove.Add(newEdge); } } foreach(KargerGraphEdge edgeToRemove in edgesToRemove) { edge.FromVertex.Edges.Remove(edgeToRemove); graph.Edges.Remove(edgeToRemove); } }
/// <summary> /// Runs Karger's algorithm on a graph (that respresents a list of polygons) once, which splits a cluster of polygons into two random parts. https://en.wikipedia.org/wiki/Karger%27s_algorithm /// Returns two new lists with the splitted continents /// </summary> private static KargerGraph SplitClusterOnce(List<GraphPolygon> cluster) { // First we need to turn the cluster into a Karger graph (which is just a regular unweighted undirected graph), where the nodes contain information about which polygons they contain KargerGraph graph = new KargerGraph(); Dictionary<GraphPolygon, KargerGraphVertex> vertices = new Dictionary<GraphPolygon, KargerGraphVertex>(); foreach (GraphPolygon poly in cluster) { KargerGraphVertex vertex = new KargerGraphVertex(poly); graph.Vertices.Add(vertex); vertices.Add(poly, vertex); } List<GraphPolygon> visitedPolygons = new List<GraphPolygon>(); foreach(GraphPolygon poly in cluster) { visitedPolygons.Add(poly); foreach(GraphPolygon neighbourPoly in poly.LandNeighbours.Where(x => cluster.Contains(x) && !visitedPolygons.Contains(x))) { KargerGraphEdge edge = new KargerGraphEdge(vertices[poly], vertices[neighbourPoly]); graph.Edges.Add(edge); vertices[poly].Edges.Add(edge); vertices[neighbourPoly].Edges.Add(edge); } } // Debug graph /* foreach(KargerGraphEdge edge in graph.Edges) { Vector2 from = edge.FromVertex.ContainedPolygons[0].CenterPoi; Vector2 to = edge.ToVertex.ContainedPolygons[0].CenterPoi; Debug.DrawLine(new Vector3(from.x, 0f, from.y), new Vector3(to.x, 0f, to.y), Color.red, 30); } */ // Then collapse edges in the graph until only 2 vertices are left while(graph.Vertices.Count > 2) { KargerGraphEdge randomEdge = graph.Edges[Random.Range(0, graph.Edges.Count)]; CollapseEdge(graph, randomEdge); } graph.CutSize = graph.Vertices[0].Edges.Count; return graph; }