mirror of
https://github.com/TheAlgorithms/Python.git
synced 2024-11-30 16:31:08 +00:00
Improve comments, add doctests to coloring.py
This commit is contained in:
parent
a9ca110d6b
commit
4de67b014c
|
@ -1,7 +1,7 @@
|
|||
"""
|
||||
Graph Coloring also called "m coloring problem"
|
||||
consists of coloring a given graph with at most m colors
|
||||
such that no adjacent vertices are assigned the same color
|
||||
Graph Coloring (also called the "m coloring problem") is the problem of
|
||||
assigning at most 'm' colors to the vertices of a graph such that
|
||||
no two adjacent vertices share the same color.
|
||||
|
||||
Wikipedia: https://en.wikipedia.org/wiki/Graph_coloring
|
||||
"""
|
||||
|
@ -11,13 +11,27 @@ def valid_coloring(
|
|||
neighbours: list[int], colored_vertices: list[int], color: int
|
||||
) -> bool:
|
||||
"""
|
||||
This function checks if a given vertex can be assigned the specified color
|
||||
without violating the graph coloring constraints (i.e., no two adjacent vertices
|
||||
have the same color).
|
||||
|
||||
Procedure:
|
||||
For each neighbour check if the coloring constraint is satisfied
|
||||
If any of the neighbours fail the constraint return False
|
||||
If all neighbours validate the constraint return True
|
||||
|
||||
>>> neighbours = [0,1,0,1,0]
|
||||
>>> colored_vertices = [0, 2, 1, 2, 0]
|
||||
Parameters:
|
||||
neighbours (list[int]): The list representing which vertices are adjacent to the current vertex.
|
||||
1 indicates an edge between the current vertex and the neighbour.
|
||||
colored_vertices (list[int]): List of current color assignments for all vertices (-1 means uncolored).
|
||||
color (int): The color we are trying to assign to the current vertex.
|
||||
|
||||
Returns:
|
||||
bool: True if the vertex can be safely colored with the given color, otherwise False.
|
||||
|
||||
Examples:
|
||||
>>> neighbours = [0, 1, 0, 1, 0]
|
||||
>>> colored_vertices = [0, 2, 1, 2, 0]
|
||||
>>> color = 1
|
||||
>>> valid_coloring(neighbours, colored_vertices, color)
|
||||
True
|
||||
|
@ -25,8 +39,14 @@ def valid_coloring(
|
|||
>>> color = 2
|
||||
>>> valid_coloring(neighbours, colored_vertices, color)
|
||||
False
|
||||
|
||||
>>> neighbors = [1, 0, 1, 0]
|
||||
>>> colored_vertices = [-1, -1, -1, -1]
|
||||
>>> color = 0
|
||||
>>> valid_coloring(neighbors, colored_vertices, color)
|
||||
True
|
||||
"""
|
||||
# Does any neighbour not satisfy the constraints
|
||||
# Check if any adjacent vertex has already been colored with the same color
|
||||
return not any(
|
||||
neighbour == 1 and colored_vertices[i] == color
|
||||
for i, neighbour in enumerate(neighbours)
|
||||
|
@ -37,7 +57,7 @@ def util_color(
|
|||
graph: list[list[int]], max_colors: int, colored_vertices: list[int], index: int
|
||||
) -> bool:
|
||||
"""
|
||||
Pseudo-Code
|
||||
Recursive function to try and color the graph using backtracking.
|
||||
|
||||
Base Case:
|
||||
1. Check if coloring is complete
|
||||
|
@ -51,6 +71,18 @@ def util_color(
|
|||
2.4. if current coloring leads to a solution return
|
||||
2.5. Uncolor given vertex
|
||||
|
||||
Parameters:
|
||||
graph (list of list of int): Adjacency matrix representing the graph.
|
||||
graph[i][j] is 1 if there is an edge between vertex i and j.
|
||||
max_colors (int): Maximum number of colors allowed (m in the m-coloring problem).
|
||||
colored_vertices (list of int): Current color assignments for each vertex.
|
||||
-1 indicates that the vertex has not been colored yet.
|
||||
index (int): The current vertex index being processed.
|
||||
|
||||
Returns:
|
||||
bool: True if the graph can be colored using at most max_colors, otherwise False.
|
||||
|
||||
Examples:
|
||||
>>> graph = [[0, 1, 0, 0, 0],
|
||||
... [1, 0, 1, 0, 1],
|
||||
... [0, 1, 0, 1, 0],
|
||||
|
@ -67,36 +99,45 @@ def util_color(
|
|||
>>> util_color(graph, max_colors, colored_vertices, index)
|
||||
False
|
||||
"""
|
||||
|
||||
# Base Case
|
||||
# Base Case: If all vertices have been assigned a color, we have a valid solution
|
||||
if index == len(graph):
|
||||
return True
|
||||
|
||||
# Recursive Step
|
||||
for i in range(max_colors):
|
||||
if valid_coloring(graph[index], colored_vertices, i):
|
||||
# Color current vertex
|
||||
colored_vertices[index] = i
|
||||
# Validate coloring
|
||||
# Try each color for the current vertex
|
||||
for color in range(max_colors):
|
||||
# Check if it's valid to color the current vertex with 'color'
|
||||
if valid_coloring(graph[index], colored_vertices, color):
|
||||
colored_vertices[index] = color # Assign color
|
||||
# Recur to color the rest of the vertices
|
||||
if util_color(graph, max_colors, colored_vertices, index + 1):
|
||||
return True
|
||||
# Backtrack
|
||||
# Backtrack if no solution found with the current assignment
|
||||
colored_vertices[index] = -1
|
||||
return False
|
||||
|
||||
return False # Return False if no valid coloring is possible
|
||||
|
||||
|
||||
def color(graph: list[list[int]], max_colors: int) -> list[int]:
|
||||
"""
|
||||
Wrapper function to call subroutine called util_color
|
||||
which will either return True or False.
|
||||
If True is returned colored_vertices list is filled with correct colorings
|
||||
Attempts to color the graph with at most max_colors colors such that no two adjacent
|
||||
vertices have the same color. If it is possible, returns the list of color assignments;
|
||||
otherwise, returns an empty list.
|
||||
|
||||
Parameters:
|
||||
graph (list of list of int): Adjacency matrix representing the graph.
|
||||
max_colors (int): Maximum number of colors allowed.
|
||||
|
||||
Returns:
|
||||
list of int: List of color assignments if the graph can be colored using max_colors.
|
||||
Each index in the list represents the color assigned to the corresponding vertex.
|
||||
If coloring is not possible, returns an empty list.
|
||||
|
||||
Examples:
|
||||
>>> graph = [[0, 1, 0, 0, 0],
|
||||
... [1, 0, 1, 0, 1],
|
||||
... [0, 1, 0, 1, 0],
|
||||
... [0, 1, 1, 0, 0],
|
||||
... [0, 1, 0, 0, 0]]
|
||||
|
||||
>>> max_colors = 3
|
||||
>>> color(graph, max_colors)
|
||||
[0, 1, 0, 2, 0]
|
||||
|
@ -104,10 +145,26 @@ def color(graph: list[list[int]], max_colors: int) -> list[int]:
|
|||
>>> max_colors = 2
|
||||
>>> color(graph, max_colors)
|
||||
[]
|
||||
|
||||
>>> graph = [[0, 1], [1, 0]] # Simple 2-node graph
|
||||
>>> max_colors = 2
|
||||
>>> color(graph, max_colors)
|
||||
[0, 1]
|
||||
|
||||
>>> graph = [[0, 1, 1], [1, 0, 1], [1, 1, 0]] # Complete graph of 3 vertices
|
||||
>>> max_colors = 2
|
||||
>>> color(graph, max_colors)
|
||||
[]
|
||||
|
||||
>>> max_colors = 3
|
||||
>>> color(graph, max_colors)
|
||||
[0, 1, 2]
|
||||
"""
|
||||
# Initialize all vertices as uncolored (-1)
|
||||
colored_vertices = [-1] * len(graph)
|
||||
|
||||
# Use the utility function to try and color the graph starting from vertex 0
|
||||
if util_color(graph, max_colors, colored_vertices, 0):
|
||||
return colored_vertices
|
||||
return colored_vertices # Return the successful color assignment
|
||||
|
||||
return []
|
||||
return [] # Return an empty list if no valid coloring is possible
|
||||
|
|
Loading…
Reference in New Issue
Block a user