Open In App

Chromatic Number of a Graph | Graph Colouring

Last Updated : 29 Feb, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

Graph coloring is a fundamental concept in graph theory, and the chromatic number is a key parameter that quantifies the coloring properties of a graph. Let’s go into the introductory aspects of the chromatic number.

Graph coloring refers to the problem of coloring vertices of a graph in such a way that no two adjacent vertices have the same color. This is also called the vertex coloring problem. If coloring is done using at most m colors, it is called m-coloring.

What is Chromatic Number?

The chromatic number of a graph G, denoted as χ(G), is the minimum number of colors required to color the vertices of a graph G in such a way that no two adjacent vertices share the same color. Formally, it is the smallest positive integer k for which there exists a proper vertex coloring with k colors.

  • The chromatic number is an essential parameter that captures the inherent colorability of a graph.
  • It provides insights into the structural properties and relationships within the graph.

Vertex Coloring:

  • A vertex coloring of a graph assigns colors to its vertices in a way that no two adjacent vertices have the same color.
  • Proper vertex coloring ensures that adjacent vertices have distinct colors.

Chromatic Number of Cyclic Graph:

A graph is known as a cycle graph if it contains ‘n’ edges and ‘n’ vertices (n >= 3), which form a cycle of length ‘n’. The chromatic number in a cycle graph depends upon the parity of cycle length:

Case 1 (Odd length cycle): χ(G) = 3.

Case 2(Even length cycle): χ(G) = 2.

Chromatic Number of Complete Graph:

The chromatic number of a complete graph is equal to the number of vertices in the graph.

Chromatic Number of Bipartite Graph:

Non-empty bipartite graphs have a chromatic number of 2.

since the two parts are each independent sets and can be colored with a single color. Conversely, if a graph can be 2-colored, it is bipartite, since all edges connect vertices of different colors

Chromatic Number of Star Graph:

The chromatic number of a star graph is 2.

Chromatic Number of Wheel Graph:

The chromatic number of a wheel graph is 3 if the number of vertices is even, and 4 if the number of vertices is odd.

Chromatic Number of Planar Graph:

A Planar Graph is a graph that can be drawn in a plane such that none of its edges cross each other.

χ(Planar Graph) <= 4

χ(Trees) = 2.

Properites of Chromatic Number:

Here are some properties of the chromatic number:

  • Upper Bounds: The chromatic number of a graph is at most the maximum vertex degree, unless the graph is complete or an odd cycle, in which case the chromatic number is equal to the maximum vertex degree plus one2. This is known as Brooks’ theorem2.
  • Lower Bounds: The chromatic number of a graph is at least the size of the largest clique in the graph3. A clique is a subset of vertices of an undirected graph such that every two distinct vertices in the clique are adjacent3.
  • Bicolorable Graphs: A graph with a chromatic number of 2 is said to be bicolorable2. This means that the vertices of the graph can be colored using only two colors in such a way that no two adjacent vertices share the same color2.
  • Three-colorable Graphs: A graph with a chromatic number of 3 is said to be three-colorable2. This means that the vertices of the graph can be colored using only three colors in such a way that no two adjacent vertices share the same color2.
  • Complete Graphs: The chromatic number of a complete graph is equal to the number of vertices in the graph1. A complete graph is a simple undirected graph in which every pair of distinct vertices is connected by a unique edge1.
  • Cycle Graphs: The chromatic number of a cycle graph is 2 if the number of vertices in the graph is even, and 3 if the number of vertices in the graph is odd1.
  • Edgeless Graphs: The only graphs that can be 1-colored are edgeless graphs3. An edgeless graph is a graph with no edges3

Importance of Chromatic Number in Graph Theory:

  • Graph Labeling: Chromatic number is a form of graph labeling, which is crucial in representing and analyzing graphs.
  • Map Coloring Problem: The chromatic number is directly related to the classic map coloring problem, where the goal is to color regions of a map (represented as vertices) such that no two adjacent regions share the same color.
  • Graph Classifications: Graphs with low chromatic numbers often have special properties. For example, trees are 2-colorable (have chromatic number 2), and bipartite graphs have chromatic number 2.
  • Algorithmic Applications: Graph coloring algorithms, including those based on chromatic number, are used in scheduling problems, register allocation in compilers, and various optimization tasks.
  • Connection to Combinatorial Problems: The chromatic number is linked to combinatorial questions, such as finding the minimum number of colors needed to color a graph or identifying graphs with specific colorability properties.
  • Broader Graph Theory Concepts: The chromatic number is intertwined with other graph parameters and theorems, contributing to a deeper understanding of graph theory.

Algorithm to Find Chromatic Numbers:

There are several algorithms to find the chromatic number of a graph, each with its own strengths and weaknesses in terms of complexity:

1. Finding Chromatic Numbers using Greedy Algorithm:

  • Idea: Assign colors to vertices sequentially, choosing the first available color (not used by any neighbors) for each vertex.
  • Complexity: O(V + E), where V is the number of vertices and E is the number of edges.
  • Pros: Simple to implement, fast for sparse graphs.
  • Cons: Doesn’t guarantee optimal solution for all graphs, often overestimates the chromatic number.

Implementation:

C++




#include <algorithm>
#include <iostream>
#include <unordered_set>
#include <vector>
 
using namespace std;
 
// Function to find the chromatic number using the greedy
// coloring algorithm
int greedyColoring(const vector<vector<int> >& graph)
{
    int n = graph.size();
    vector<int> colors(n, -1);
 
    for (int v = 0; v < n; ++v) {
        unordered_set<int> usedColors;
 
        // Check neighbors and mark their colors as used
        for (int neighbor : graph[v]) {
            if (colors[neighbor] != -1) {
                usedColors.insert(colors[neighbor]);
            }
        }
 
        // Find the smallest available color
        for (int color = 1;; ++color) {
            if (usedColors.find(color)
                == usedColors.end()) {
                colors[v] = color;
                break;
            }
        }
    }
 
    // Find the maximum color used (chromatic number)
    int chromaticNumber
        = *max_element(colors.begin(), colors.end()) + 1;
    return chromaticNumber;
}
 
int main()
{
    // Sample graph represented as an adjacency list
    vector<vector<int> > graph
        = { { 1, 2, 3 }, { 0, 2 }, { 0, 1, 3 }, { 0, 2 } };
 
    // Find and output the chromatic number
    int chromaticNumber = greedyColoring(graph);
    cout << "Chromatic Number: " << chromaticNumber << endl;
 
    return 0;
}


Java




// Java Implementation
 
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
 
public class GreedyColoring {
 
    // Function to find the chromatic number using the greedy
    // coloring algorithm
    public static int greedyColoring(List<List<Integer>> graph) {
        int n = graph.size();
        int[] colors = new int[n];
        for (int i = 0; i < n; i++) {
            colors[i] = -1;
        }
 
        for (int v = 0; v < n; v++) {
            Set<Integer> usedColors = new HashSet<>();
 
            // Check neighbors and mark their colors as used
            for (int neighbor : graph.get(v)) {
                if (colors[neighbor] != -1) {
                    usedColors.add(colors[neighbor]);
                }
            }
 
            // Find the smallest available color
            int color;
            for (color = 1; ; color++) {
                if (!usedColors.contains(color)) {
                    colors[v] = color;
                    break;
                }
            }
        }
 
        // Find the maximum color used (chromatic number)
        int chromaticNumber = 0;
        for (int color : colors) {
            chromaticNumber = Math.max(chromaticNumber, color);
        }
        return chromaticNumber + 1;
    }
 
    public static void main(String[] args) {
        // Sample graph represented as an adjacency list
        List<List<Integer>> graph = new ArrayList<>();
        graph.add(new ArrayList<>(List.of(1, 2, 3)));
        graph.add(new ArrayList<>(List.of(0, 2)));
        graph.add(new ArrayList<>(List.of(0, 1, 3)));
        graph.add(new ArrayList<>(List.of(0, 2)));
 
        // Find and output the chromatic number
        int chromaticNumber = greedyColoring(graph);
        System.out.println("Chromatic Number: " + chromaticNumber);
    }
}
 
 
// This code is contributed by Tapesh(tapeshdu420)


C#




using System;
using System.Collections.Generic;
using System.Linq;
 
public class GreedyColoring
{
    // Function to find the chromatic number using the greedy
    // coloring algorithm
    public static int FindChromaticNumber(List<List<int>> graph)
    {
        int n = graph.Count;
        int[] colors = new int[n];
        for (int i = 0; i < n; i++)
        {
            colors[i] = -1;
        }
 
        for (int v = 0; v < n; v++)
        {
            HashSet<int> usedColors = new HashSet<int>();
 
            // Check neighbors and mark their colors as used
            foreach (int neighbor in graph[v])
            {
                if (colors[neighbor] != -1)
                {
                    usedColors.Add(colors[neighbor]);
                }
            }
 
            // Find the smallest available color
            int color;
            for (color = 1; ; color++)
            {
                if (!usedColors.Contains(color))
                {
                    colors[v] = color;
                    break;
                }
            }
        }
 
        // Find the maximum color used (chromatic number)
        int chromaticNumber = colors.Max();
        return chromaticNumber + 1;
    }
 
    public static void Main(string[] args)
    {
        // Sample graph represented as an adjacency list
        List<List<int>> graph = new List<List<int>>
        {
            new List<int> { 1, 2, 3 },
            new List<int> { 0, 2 },
            new List<int> { 0, 1, 3 },
            new List<int> { 0, 2 }
        };
 
        // Find and output the chromatic number
        int chromaticNumber = FindChromaticNumber(graph);
        Console.WriteLine("Chromatic Number: " + chromaticNumber);
    }
}


Javascript




// Function to find the chromatic number
// using the greedy coloring algorithm
function greedyColoring(graph) {
    const n = graph.length;
    const colors = new Array(n).fill(-1);
 
    for (let v = 0; v < n; ++v) {
        const usedColors = new Set();
 
        // Check neighbors and mark
        // their colors as used
        for (const neighbor of graph[v]) {
            if (colors[neighbor] !== -1) {
                usedColors.add(colors[neighbor]);
            }
        }
 
        // Find the smallest available
        // color
        let color = 1;
        while (true) {
            if (!usedColors.has(color)) {
                colors[v] = color;
                break;
            }
            color++;
        }
    }
 
    // Find the maximum color used
    // (chromatic number)
    const chromaticNumber = Math.max(...colors) + 1;
    return chromaticNumber;
}
 
// Sample graph represented as an
// adjacency list
const graph = [
    [1, 2, 3],
    [0, 2],
    [0, 1, 3],
    [0, 2]
];
 
// Find and output the chromatic number
const chromaticNumber = greedyColoring(graph);
console.log("Chromatic Number: " + chromaticNumber);


Python3




def greedy_coloring(graph):
    n = len(graph)
    colors = [-1] * n
 
    for v in range(n):
        used_colors = set()
 
        # Check neighbors and mark their colors as used
        for neighbor in graph[v]:
            if colors[neighbor] != -1:
                used_colors.add(colors[neighbor])
 
        # Find the smallest available color
        color = 1
        while True:
            if color not in used_colors:
                colors[v] = color
                break
            color += 1
 
    # Find the maximum color used (chromatic number)
    chromatic_number = max(colors) + 1
    return chromatic_number
 
# Sample graph represented as an adjacency list
graph = [[1, 2, 3], [0, 2], [0, 1, 3], [0, 2]]
 
# Find and output the chromatic number
chromatic_number = greedy_coloring(graph)
print("Chromatic Number:", chromatic_number)


Output

Chromatic Number: 4





2. Finding Chromatic Numbers using Backtracking Algorithm:

  • Idea: Systematically explore all possible colorings by assigning colors to each vertex and backtracking if an invalid coloring is encountered.
  • Complexity: O(V! * K^V), where K is the number of available colors and V is the number of vertices. This can be exponential for large graphs.
  • Pros: Guarantees optimal solution, can be modified for specific constraints.
  • Cons: Very slow for large graphs, impractical for real-world scenarios.

Implementation:

C++




#include <iostream>
#include <unordered_set>
#include <vector>
 
using namespace std;
 
// Function to check if it's safe to color a vertex with a
// given color
bool isSafe(int v, const vector<vector<int> >& graph,
            const vector<int>& color, int c)
{
    for (int neighbor : graph[v]) {
        if (color[neighbor] == c) {
            return false; // If any adjacent vertex has the
                        // same color, it's not safe
        }
    }
    return true;
}
 
// Backtracking function to find a valid coloring
bool graphColoringUtil(int v,
                    const vector<vector<int> >& graph,
                    vector<int>& color, int m)
{
    if (v == graph.size()) {
        return true; // All vertices are colored, a solution
                    // is found
    }
 
    for (int c = 1; c <= m; ++c) {
        if (isSafe(v, graph, color, c)) {
            color[v] = c;
 
            // Recur for the next vertices
            if (graphColoringUtil(v + 1, graph, color, m)) {
                return true;
            }
 
            // Backtrack
            color[v] = 0;
        }
    }
 
    return false; // No solution found for this coloring
}
 
// Main function to find chromatic number
int graphColoring(const vector<vector<int> >& graph, int m)
{
    int n = graph.size();
    vector<int> color(n, 0);
 
    if (!graphColoringUtil(0, graph, color, m)) {
        cout << "No feasible solution exists";
        return 0;
    }
 
    // Print the solution
    cout << "Vertex colors: ";
    for (int c : color) {
        cout << c << " ";
    }
    cout << endl;
 
    // Count unique colors to determine chromatic number
    unordered_set<int> uniqueColors(color.begin(),
                                    color.end());
    return uniqueColors.size();
}
 
int main()
{
    // Sample graph represented as an adjacency list
    vector<vector<int> > graph
        = { { 1, 2, 3 }, { 0, 2 }, { 0, 1, 3 }, { 0, 2 } };
 
    // Set the maximum number of colors
    int maxColors = 3;
 
    // Find and output the chromatic number
    int chromaticNumber = graphColoring(graph, maxColors);
    cout << "Chromatic Number: " << chromaticNumber << endl;
 
    return 0;
}


Java




import java.util.*;
 
public class GraphColoring {
    // Function to check if it's safe to color a vertex with a given color
    static boolean isSafe(int v, List<List<Integer>> graph, int[] color, int c) {
        for (int neighbor : graph.get(v)) {
            if (color[neighbor] == c) {
                return false; // If any adjacent vertex has the same color, it's not safe
            }
        }
        return true;
    }
 
    // Backtracking function to find a valid coloring
    static boolean graphColoringUtil(int v, List<List<Integer>> graph, int[] color, int m) {
        if (v == graph.size()) {
            return true; // All vertices are colored, a solution is found
        }
 
        for (int c = 1; c <= m; ++c) {
            if (isSafe(v, graph, color, c)) {
                color[v] = c;
 
                // Recur for the next vertices
                if (graphColoringUtil(v + 1, graph, color, m)) {
                    return true;
                }
 
                // Backtrack
                color[v] = 0;
            }
        }
 
        return false; // No solution found for this coloring
    }
 
    // Main function to find chromatic number
    static int graphColoring(List<List<Integer>> graph, int m) {
        int n = graph.size();
        int[] color = new int[n];
 
        if (!graphColoringUtil(0, graph, color, m)) {
            System.out.println("No feasible solution exists");
            return 0;
        }
 
        // Print the solution
        StringBuilder result = new StringBuilder("Vertex colors: ");
        for (int c : color) {
            result.append(c).append(" ");
        }
        System.out.println(result);
 
        // Count unique colors to determine chromatic number
        Set<Integer> uniqueColors = new HashSet<>();
        for (int c : color) {
            uniqueColors.add(c);
        }
        return uniqueColors.size();
    }
 
    // Main function
    public static void main(String[] args) {
        // Sample graph represented as an adjacency list
        List<List<Integer>> graph = new ArrayList<>();
        graph.add(Arrays.asList(1, 2, 3));
        graph.add(Arrays.asList(0, 2));
        graph.add(Arrays.asList(0, 1, 3));
        graph.add(Arrays.asList(0, 2));
 
        // Set the maximum number of colors
        int maxColors = 3;
 
        // Find and output the chromatic number
        int chromaticNumber = graphColoring(graph, maxColors);
        System.out.println("Chromatic Number: " + chromaticNumber);
    }
}


C#




using System;
using System.Collections.Generic;
 
class Program {
    // Function to check if it's safe to color a vertex with
    // a given color
    static bool IsSafe(int v, List<List<int> > graph,
                       List<int> color, int c)
    {
        foreach(int neighbor in graph[v])
        {
            if (color[neighbor] == c) {
                return false; // If any adjacent vertex has
                              // the same color, it's not
                              // safe
            }
        }
        return true;
    }
 
    // Backtracking function to find a valid coloring
    static bool GraphColoringUtil(int v,
                                  List<List<int> > graph,
                                  List<int> color, int m)
    {
        if (v == graph.Count) {
            return true; // All vertices are colored, a
                         // solution is found
        }
 
        for (int c = 1; c <= m; ++c) {
            if (IsSafe(v, graph, color, c)) {
                color[v] = c;
 
                // Recur for the next vertices
                if (GraphColoringUtil(v + 1, graph, color,
                                      m)) {
                    return true;
                }
 
                // Backtrack
                color[v] = 0;
            }
        }
 
        return false; // No solution found for this coloring
    }
 
    // Main function to find chromatic number
    static int GraphColoring(List<List<int> > graph, int m)
    {
        int n = graph.Count;
        List<int> color = new List<int>(new int[n]);
 
        if (!GraphColoringUtil(0, graph, color, m)) {
            Console.WriteLine(
                "No feasible solution exists");
            return 0;
        }
 
        // Print the solution
        Console.Write("Vertex colors: ");
        foreach(int c in color) { Console.Write(c + " "); }
        Console.WriteLine();
 
        // Count unique colors to determine chromatic number
        HashSet<int> uniqueColors = new HashSet<int>(color);
        return uniqueColors.Count;
    }
 
    static void Main(string[] args)
    {
        // Sample graph represented as an adjacency list
        List<List<int> > graph = new List<List<int> >{
            new List<int>{ 1, 2, 3 }, new List<int>{ 0, 2 },
            new List<int>{ 0, 1, 3 }, new List<int>{ 0, 2 }
        };
 
        // Set the maximum number of colors
        int maxColors = 3;
 
        // Find and output the chromatic number
        int chromaticNumber
            = GraphColoring(graph, maxColors);
        Console.WriteLine("Chromatic Number: "
                          + chromaticNumber);
    }
}


Javascript




// Function to check if it's safe to color a vertex with a given color
function isSafe(v, graph, color, c) {
    for (let neighbor of graph[v]) {
        if (color[neighbor] === c) {
            return false; // If any adjacent vertex has the same color, it's not safe
        }
    }
    return true;
}
 
// Backtracking function to find a valid coloring
function graphColoringUtil(v, graph, color, m) {
    if (v === graph.length) {
        return true; // All vertices are colored, a solution is found
    }
 
    for (let c = 1; c <= m; ++c) {
        if (isSafe(v, graph, color, c)) {
            color[v] = c;
 
            // Recur for the next vertices
            if (graphColoringUtil(v + 1, graph, color, m)) {
                return true;
            }
 
            // Backtrack
            color[v] = 0;
        }
    }
 
    return false; // No solution found for this coloring
}
 
// Main function to find chromatic number
function graphColoring(graph, m) {
    const n = graph.length;
    const color = new Array(n).fill(0);
 
    if (!graphColoringUtil(0, graph, color, m)) {
        console.log("No feasible solution exists");
        return 0;
    }
 
    // Print the solution
    let result = "Vertex colors: ";
    for (let c of color) {
        result += c + " ";
    }
    console.log(result);
 
    // Count unique colors to determine chromatic number
    const uniqueColors = new Set(color);
    return uniqueColors.size;
}
 
// Main function
function main() {
    // Sample graph represented as an adjacency list
    const graph = [[1, 2, 3], [0, 2], [0, 1, 3], [0, 2]];
 
    // Set the maximum number of colors
    const maxColors = 3;
 
    // Find and output the chromatic number
    const chromaticNumber = graphColoring(graph, maxColors);
    console.log("Chromatic Number: " + chromaticNumber);
}
 
// Call the main function
main();


Python3




from typing import List, Set
 
def is_safe(v, graph, color, c):
    for neighbor in graph[v]:
        if color[neighbor] == c:
            return False  # If any adjacent vertex has the same color, it's not safe
    return True
 
def graph_coloring_util(v, graph, color, m):
    if v == len(graph):
        return True  # All vertices are colored, a solution is found
 
    for c in range(1, m + 1):
        if is_safe(v, graph, color, c):
            color[v] = c
 
            # Recur for the next vertices
            if graph_coloring_util(v + 1, graph, color, m):
                return True
 
            # Backtrack
            color[v] = 0
 
    return False  # No solution found for this coloring
 
def graph_coloring(graph, m):
    n = len(graph)
    color = [0] * n
 
    if not graph_coloring_util(0, graph, color, m):
        print("No feasible solution exists")
        return 0
 
    # Print the solution
    print("Vertex colors:", end=" ")
    for c in color:
        print(c, end=" ")
    print()
 
    # Count unique colors to determine chromatic number
    unique_colors = set(color)
    return len(unique_colors)
 
if __name__ == "__main__":
    # Sample graph represented as an adjacency list
    graph = [[1, 2, 3], [0, 2], [0, 1, 3], [0, 2]]
 
    # Set the maximum number of colors
    max_colors = 3
 
    # Find and output the chromatic number
    chromatic_number = graph_coloring(graph, max_colors)
    print("Chromatic Number:", chromatic_number)


Output

Vertex colors: 1 2 3 2 
Chromatic Number: 3

3. Finding Chromatic Numbers using Heuristic Algorithms:

  • Idea: Utilize various heuristics to guide the search for a valid coloring, often combining greedy approaches with elements of backtracking or other techniques.
  • Examples: Simulated annealing, genetic algorithms, tabu search.
  • Complexity: Varies depending on the specific heuristic, usually between O(V * E) and O(V! * K^V).
  • Pros: Can find good solutions for large graphs in reasonable time, offer a balance between speed and accuracy.
  • Cons: No guarantee of optimality, performance depends on the chosen heuristic and its parameters.

4. Finding Chromatic Numbers using Exact Algorithms:

  • Examples: Branch and bound, integer linear programming.
  • Complexity: Typically exponential in the worst case, but can be effective for specific graph classes.
  • Pros: Guaranteed to find the optimal solution, valuable for theoretical understanding.
  • Cons: Computationally expensive, often impractical for large graphs due to high runtime.

Choosing the right algorithm for finding chromatic number depends on the specific graph:

  • For small graphs or quick estimates, a greedy algorithm might be sufficient.
  • For optimal solutions and theoretical insights, consider exact algorithms, but be aware of their computational limitations.
  • For large graphs and a good balance between speed and accuracy, heuristic algorithms are often the best choice.

Relation between chromatic number and chromatic polynomial:

The Chromatic Number (χ) and Chromatic Polynomial (P(G, λ)) of a graph are two fascinating concepts in graph theory, each revealing different aspects of a graph’s colorability. While they seem unrelated at first glance, they share a deep and intriguing connection.

Chromatic Number:

  • Tells you the minimum number of colors needed to color the graph’s vertices without adjacent vertices sharing the same color.
  • Represents the “practical” aspect of coloring, focusing on the minimum number of palettes required.

Chromatic Polynomial:

  • Encodes much more information about the graph’s possible colorings, not just the minimum number.
  • It’s a function of a variable (λ) that represents the number of valid colorings for a graph with λ available colors.
  • Provides insights into the distribution of colorings, including the number of colorings with a specific number of colors.

Relation/Connection between Chromatic number and Chromatic polynomial

  • Fundamental Relationship: The Chromatic Number is the smallest positive integer λ for which P(G, λ) is non-zero. This means the polynomial tells you when a valid coloring with λ colors exists, and the first color where such a coloring is possible is the Chromatic Number.
  • Encoding Coloring Information: The coefficients of the polynomial represent the number of valid colorings with a specific number of colors. This allows you to analyze the “spectrum” of colorings for a graph, beyond just the minimum.
  • Applications: The polynomial can be used to prove theorems about graph coloring, analyze the complexity of different colorability problems, and even understand the structure of graphs through their colorings.

Analogy:

Imagine the Chromatic Number as the “minimum number of paint buckets” you need to color a graph. The Chromatic Polynomial, on the other hand, is like a “painting inventory” that tells you how many different ways you can paint the graph with different numbers of buckets available.

Introduction to Graph Coloring

M-Coloring Problem

Graph Coloring Using Greedy Algorithm

Edge Coloring of a Graph

Coloring a Cycle Graph

Chromatic Polynomial



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads