coloring Algorithm
The coloring algorithm, also known as the graph coloring algorithm, is a technique used in computer science and mathematics to assign colors to the vertices of a graph in such a way that no two adjacent vertices share the same color. This algorithm is widely utilized in a variety of applications, such as scheduling problems, register allocation, frequency assignment, and more. The main goal of this algorithm is to use the minimum number of colors while ensuring that the coloring constraints are satisfied. There are several types of graph coloring algorithms, such as greedy algorithms, backtracking algorithms, and heuristics-based algorithms.
One of the most popular coloring algorithms is the greedy algorithm, which involves assigning colors to the vertices in a sequential manner. The algorithm starts with an uncolored graph and selects the first vertex, assigning it the first available color. Then, it proceeds to the next vertex and assigns the lowest numbered color that is not already assigned to any of its adjacent vertices. This process is repeated until all the vertices in the graph have been colored. Although the greedy algorithm is simple and easy to implement, it does not guarantee an optimal solution, as it may end up using more colors than necessary. To achieve better results, more advanced techniques such as backtracking and heuristics-based algorithms are employed, which involve exploring multiple possibilities and making informed decisions based on the structure and properties of the graph.
"""
Graph Coloring also called "m coloring problem"
consists of coloring given graph with at most m colors
such that no adjacent vertices are assigned same color
Wikipedia: https://en.wikipedia.org/wiki/Graph_coloring
"""
from typing import List
def valid_coloring(
neighbours: List[int], colored_vertices: List[int], color: int
) -> bool:
"""
For each neighbour check if coloring constraint is satisfied
If any of the neighbours fail the constraint return False
If all neighbours validate constraint return True
>>> neighbours = [0,1,0,1,0]
>>> colored_vertices = [0, 2, 1, 2, 0]
>>> color = 1
>>> valid_coloring(neighbours, colored_vertices, color)
True
>>> color = 2
>>> valid_coloring(neighbours, colored_vertices, color)
False
"""
# Does any neighbour not satisfy the constraints
return not any(
neighbour == 1 and colored_vertices[i] == color
for i, neighbour in enumerate(neighbours)
)
def util_color(
graph: List[List[int]], max_colors: int, colored_vertices: List[int], index: int
) -> bool:
"""
Pseudo-Code
Base Case:
1. Check if coloring is complete
1.1 If complete return True (meaning that we successfully colored graph)
Recursive Step:
2. Itterates over each color:
Check if current coloring is valid:
2.1. Color given vertex
2.2. Do recursive call check if this coloring leads to solving problem
2.4. if current coloring leads to solution return
2.5. Uncolor given vertex
>>> 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
>>> colored_vertices = [0, 1, 0, 0, 0]
>>> index = 3
>>> util_color(graph, max_colors, colored_vertices, index)
True
>>> max_colors = 2
>>> util_color(graph, max_colors, colored_vertices, index)
False
"""
# Base Case
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
if util_color(graph, max_colors, colored_vertices, index + 1):
return True
# Backtrack
colored_vertices[index] = -1
return False
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
>>> 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]
>>> max_colors = 2
>>> color(graph, max_colors)
[]
"""
colored_vertices = [-1] * len(graph)
if util_color(graph, max_colors, colored_vertices, 0):
return colored_vertices
return []