Key takeaways
Graph coloring labels vertices so no two adjacent ones share the same color, aiming for the minimum number of colors.
Types
Vertex coloring: This colors vertices with no adjacent sharing.
Edge coloring: This colors edges without sharing colors at vertices.
Face coloring: This colors regions of a planar graph without adjacent sharing.
It includes greedy coloring, backtracking, and DSatur algorithms for efficient coloring.
It is used in scheduling, register allocation, and frequency assignment in networks.
Graph coloring is a way of labeling the vertices of a graph such that no two adjacent vertices share the same label. The primary goal is to use the minimum number of colors possible. This concept is widely used in various fields such as scheduling, register allocation in compilers, and frequency assignment in wireless networks. Some key concepts and types of graph coloring are explained below:
Chromatic number: The minimum number of colors needed to color a graph is called its chromatic number.
Proper coloring: A coloring of a graph is called proper if no two adjacent vertices have the same color.
k-Colorable graph: A graph that can be colored with k colors is called a k-colorable graph.
Vertex coloring: This includes assigning colors to the vertices of the graph such that no two adjacent vertices have the same color.
Edge coloring: This includes assigning colors to the edges of the graph such that no two edges sharing the same vertex have the same color.
Face coloring: This includes coloring the regions (faces) of a planar graph such that no two regions sharing a boundary have the same color.
We'll look into a few examples to better understand the concepts related to graph coloring. First, let's try to color a graph and find its chromatic number.
The chromatic number of the above graph comes out to be 3. In addition to this, the graph illustrated above is a 3-colorable graph. However, it should be kept in mind that this graph is also 4-colorable, 5-colorable, and so on. This is because a graph that could be colored using a minimum of three colors can be easily colored using more than three colors.
Let's explore a few more examples related to graph coloring and its associated concepts.
A graph coloring algorithm is used to assign colors to the elements of a graph subject to certain constraints. The most common type of graph coloring is vertex coloring, where the goal is to assign colors to the vertices of a graph such that no two adjacent vertices share the same color.
Greedy coloring algorithm: It is a simple and fast algorithm that colors vertices one by one, always choosing the smallest available color.
Backtracking algorithm: It is an exhaustive search algorithm that tries all possible colorings and backtracks when a conflict is found, ensuring an optimal solution.
DSatur algorithm: It is a heuristic algorithm that chooses the next vertex to color based on the degree of saturation (number of different colors to which it is adjacent).
A greedy coloring algorithm assigns colors to the vertices of a graph in a way that no two adjacent vertices have the same color, using a simple heuristic approach. It proceeds by coloring the graph vertex by vertex, always choosing the smallest available color (often referred to as the 'greedy' choice).
It's time to get hands-on with implementing a graph coloring algorithm in Python.
def greedy_coloring(graph):num_vertices = len(graph)# Initialize a resultant array of size equal to the number of vertices# and initialize it with -1 representing no color is assigned to any vertexcoloring = [-1] * num_vertices# Assign the first color (0) to the first vertexcoloring[0] = 0# Assign colors to the remaining verticesfor vertex in range(1, num_vertices):# Keep a temporary list to track the available colors for each vertex# False value of available_colors[c] would mean that the color c is not available# because it's assigned to one of its neighborsavailable_colors = [True] * num_vertices# Iterate through all neighbors of a vertex and mark their colors as unavailablefor neighbor in graph[vertex]:if coloring[neighbor] != -1:available_colors[coloring[neighbor]] = False# Find the first available colorcolor = 0while color < num_vertices:if available_colors[color]:breakcolor += 1# Color the current vertex with the found colorcoloring[vertex] = colorreturn coloringdef print_graph(graph):print("Printing the graph:")for v in range(len(graph)):print(f"\tVertex {v} is connected to vertices {graph[v]}")def print_coloring(coloring):print("\nPrinting the coloring:")for v in range(len(coloring)):print(f"\tVertex {v}: Color {coloring[v]}")def main():# A simple example graph represented as adjacency listgraph = [[1, 2], # Vertex 0 is connected to vertices 1 and 2[0, 2, 3], # Vertex 1 is connected to vertices 0, 2, and 3[0, 1, 3], # Vertex 2 is connected to vertices 0, 1, and 3[1, 2]] # Vertex 3 is connected to vertices 1 and 2# Another example graph represented as adjacency list# graph = [[1, 2, 3], # Vertex 0 is connected to vertices 1, 2, and 3# [0, 2, 4], # Vertex 1 is connected to vertices 0, 2, and 4# [0, 1, 3, 4], # Vertex 2 is connected to vertices 0, 1, 3, and 4# [0, 2, 4, 5], # Vertex 3 is connected to vertices 0, 2, 4, and 5# [1, 2, 3, 5], # Vertex 4 is connected to vertices 1, 2, 3, and 5# [3, 4, 6, 7], # Vertex 5 is connected to vertices 3, 4, 6, and 7# [5, 7, 8], # Vertex 6 is connected to vertices 5, 7, and 8# [5, 6, 8], # Vertex 7 is connected to vertices 5, 6, and 8# [6, 7]] # Vertex 8 is connected to vertices 6 and 7# Print the graphprint_graph(graph)result = greedy_coloring(graph)# Print the resultprint_coloring(result)if __name__ == "__main__":main()
Let's try to understand how the above code actually finds a graph coloring.
Line 2: Calculate the number of vertices of the graph and assign it to num_vertices
.
Line 6: Initialize a resultant array, coloring
, of size num_vertices
with -1
indicating an empty color assignment for all vertices.
Line 9: Assign the first color to the first vertex.
The vertices are numbered as 0, 1, 2, 3, and so on. Similarly, the colors are numbered as 0, 1, 2, 3, and so on.
Line 12: Iterate through each vertex, vertex
, in the graph (except the first one because it has already been assigned a color) and perform the following steps:
Line 16: Initialize a temporary, available_colors
, of size num_vertices
with True
.
If available[color]
is True
, it means that color
is available to be assigned to any of its adjacent vertices.
If available[color]
is False
, it means that color
is not available as it's assigned to one of its adjacent vertices.
Lines 19–21: Check the colors of the vertices adjacent to vertex
and update available_colors
accordingly.
Lines 24–28: Find the first available color.
Line 31: Assign the found color to vertex
.
Line 33: Return coloring
.
Lines 35–38: Function to print a graph.
Lines 40–43: Function to print a graph coloring.
Lines 47–50: These show a simple example graph represented as adjacency list.
Lines 53–61: These show another example graph for you to try.
Line 64: Print the graph.
Line 66: This calls the greedy_algorithm
function.
Line 69: This prints the coloring
.
Having grasped the greedy coloring algorithm in Python, here's its implementation in five other popular programming languages for a diverse community of programmers.
function greedyColoring(graph) {const numVertices = graph.length;// Initialize a resultant array of size equal to the number of vertices// and initialize it with -1 representing no color is assigned to any vertexconst coloring = new Array(numVertices).fill(-1);// Assign the first color (0) to the first vertexcoloring[0] = 0;// Assign colors to the remaining verticesfor (let vertex = 1; vertex < numVertices; vertex++) {// Keep a temporary list to track the available colors for each vertex// False value of availableColors[c] would mean that the color c is not available// because it's assigned to one of its neighborsconst availableColors = new Array(numVertices).fill(true);// Iterate through all neighbors of a vertex and mark their colors as unavailablefor (let i = 0; i < graph[vertex].length; i++) {const neighbor = graph[vertex][i];if (coloring[neighbor] != -1) {availableColors[coloring[neighbor]] = false;}}// Find the first available colorlet color = 0;while (color < numVertices) {if (availableColors[color]) {break;}color++;}// Color the current vertex with the found colorcoloring[vertex] = color;}return coloring;}function printGraph(graph) {console.log("Printing the graph:");for (let v = 0; v < graph.length; v++) {console.log(`\tVertex ${v} is connected to vertices ${graph[v].join(', ')}`);}}function printColoring(coloring) {console.log("\nPrinting the coloring:");for (let v = 0; v < coloring.length; v++) {console.log(`\tVertex ${v}: Color ${coloring[v]}`);}}function main() {// A simple example graph represented as adjacency listconst graph = [[1, 2], // Vertex 0 is connected to vertices 1 and 2[0, 2, 3], // Vertex 1 is connected to vertices 0, 2, and 3[0, 1, 3], // Vertex 2 is connected to vertices 0, 1, and 3[1, 2] // Vertex 3 is connected to vertices 1 and 2];// Another example graph represented as adjacency list/*const graph = [[1, 2, 3], // Vertex 0 is connected to vertices 1, 2, and 3[0, 2, 4], // Vertex 1 is connected to vertices 0, 2, and 4[0, 1, 3, 4],// Vertex 2 is connected to vertices 0, 1, 3, and 4[0, 2, 4, 5],// Vertex 3 is connected to vertices 0, 2, 4, and 5[1, 2, 3, 5],// Vertex 4 is connected to vertices 1, 2, 3, and 5[3, 4, 6, 7],// Vertex 5 is connected to vertices 3, 4, 6, and 7[5, 7, 8], // Vertex 6 is connected to vertices 5, 7, and 8[5, 6, 8], // Vertex 7 is connected to vertices 5, 6, and 8[6, 7] // Vertex 8 is connected to vertices 6 and 7];*/// Print the graphprintGraph(graph);const result = greedyColoring(graph);// Print the resultprintColoring(result);}main();
Scheduling problems: It is used to assign time slots to tasks such that no two conflicting tasks are assigned the same time slot.
Register allocation: It is used to assign variables to a limited number of CPU registers in a way that minimizes conflicts.
Frequency assignment: It is used to assign frequencies to radio stations such that no two stations that are close enough interfere with each other that use the same frequency.
Free Resources