mirror of
https://github.com/TheAlgorithms/Python.git
synced 2025-01-18 16:27:02 +00:00
Karger's Algorithm (#2237)
* Add implementation of Karger's Algorithm * Remove print statement from karger's algorithm function * Fix style issues in graphs/karger.py * Change for loops to set comprehensions where appropriate in graphs/karger.py
This commit is contained in:
parent
4535283554
commit
c6c9f4707b
83
graphs/karger.py
Normal file
83
graphs/karger.py
Normal file
|
@ -0,0 +1,83 @@
|
|||
"""
|
||||
An implementation of Karger's Algorithm for partitioning a graph.
|
||||
"""
|
||||
|
||||
import random
|
||||
from typing import Dict, List, Set, Tuple
|
||||
|
||||
|
||||
# Adjacency list representation of this graph:
|
||||
# https://en.wikipedia.org/wiki/File:Single_run_of_Karger%E2%80%99s_Mincut_algorithm.svg
|
||||
TEST_GRAPH = {
|
||||
'1': ['2', '3', '4', '5'],
|
||||
'2': ['1', '3', '4', '5'],
|
||||
'3': ['1', '2', '4', '5', '10'],
|
||||
'4': ['1', '2', '3', '5', '6'],
|
||||
'5': ['1', '2', '3', '4', '7'],
|
||||
'6': ['7', '8', '9', '10', '4'],
|
||||
'7': ['6', '8', '9', '10', '5'],
|
||||
'8': ['6', '7', '9', '10'],
|
||||
'9': ['6', '7', '8', '10'],
|
||||
'10': ['6', '7', '8', '9', '3']
|
||||
}
|
||||
|
||||
|
||||
def partition_graph(graph: Dict[str, List[str]]) -> Set[Tuple[str, str]]:
|
||||
"""
|
||||
Partitions a graph using Karger's Algorithm. Implemented from
|
||||
pseudocode found here:
|
||||
https://en.wikipedia.org/wiki/Karger%27s_algorithm.
|
||||
This function involves random choices, meaning it will not give
|
||||
consistent outputs.
|
||||
|
||||
Args:
|
||||
graph: A dictionary containing adacency lists for the graph.
|
||||
Nodes must be strings.
|
||||
|
||||
Returns:
|
||||
The cutset of the cut found by Karger's Algorithm.
|
||||
|
||||
>>> graph = {'0':['1'], '1':['0']}
|
||||
>>> partition_graph(graph)
|
||||
{('0', '1')}
|
||||
"""
|
||||
# Dict that maps contracted nodes to a list of all the nodes it "contains."
|
||||
contracted_nodes = {node: {node} for node in graph}
|
||||
|
||||
graph_copy = {node: graph[node][:] for node in graph}
|
||||
|
||||
while len(graph_copy) > 2:
|
||||
|
||||
# Choose a random edge.
|
||||
u = random.choice(list(graph_copy.keys()))
|
||||
v = random.choice(graph_copy[u])
|
||||
|
||||
# Contract edge (u, v) to new node uv
|
||||
uv = u + v
|
||||
uv_neighbors = list(set(graph_copy[u] + graph_copy[v]))
|
||||
uv_neighbors.remove(u)
|
||||
uv_neighbors.remove(v)
|
||||
graph_copy[uv] = uv_neighbors
|
||||
for neighbor in uv_neighbors:
|
||||
graph_copy[neighbor].append(uv)
|
||||
|
||||
contracted_nodes[uv] = {contracted_node for contracted_node in
|
||||
contracted_nodes[u].union(contracted_nodes[v])}
|
||||
|
||||
# Remove nodes u and v.
|
||||
del graph_copy[u]
|
||||
del graph_copy[v]
|
||||
for neighbor in uv_neighbors:
|
||||
if u in graph_copy[neighbor]:
|
||||
graph_copy[neighbor].remove(u)
|
||||
if v in graph_copy[neighbor]:
|
||||
graph_copy[neighbor].remove(v)
|
||||
|
||||
# Find cutset.
|
||||
groups = [contracted_nodes[node] for node in graph_copy]
|
||||
return {(node, neighbor) for node in groups[0]
|
||||
for neighbor in graph[node] if neighbor in groups[1]}
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(partition_graph(TEST_GRAPH))
|
Loading…
Reference in New Issue
Block a user