我们在上一篇文章中介绍了图形着色和应用。正如在上一篇文章中所讨论的,图形着色被广泛使用。不幸的是,由于该问题是已知的 NP Complete 问题,因此没有有效的算法可用于为具有最少颜色数量的图形着色。不过,有一些近似算法可以解决这个问题。以下是分配颜色的基本贪心算法。它不保证使用最少的颜色,但它保证了颜色数量的上限。基本算法从不使用超过 d+1 种颜色,其中 d 是给定图中顶点的最大度数。
基本贪心着色算法:
1. Color first vertex with first color.
2. Do following for remaining V-1 vertices.
….. a) Consider the currently picked vertex and color it with the
lowest numbered color that has not been used on any previously
colored vertices adjacent to it. If all previously used colors
appear on vertices adjacent to v, assign a new color to it.
下面是上述贪心算法的实现。
C++
// A C++ program to implement greedy algorithm for graph coloring
#include
#include
using namespace std;
// A class that represents an undirected graph
class Graph
{
int V; // No. of vertices
list *adj; // A dynamic array of adjacency lists
public:
// Constructor and destructor
Graph(int V) { this->V = V; adj = new list[V]; }
~Graph() { delete [] adj; }
// function to add an edge to graph
void addEdge(int v, int w);
// Prints greedy coloring of the vertices
void greedyColoring();
};
void Graph::addEdge(int v, int w)
{
adj[v].push_back(w);
adj[w].push_back(v); // Note: the graph is undirected
}
// Assigns colors (starting from 0) to all vertices and prints
// the assignment of colors
void Graph::greedyColoring()
{
int result[V];
// Assign the first color to first vertex
result[0] = 0;
// Initialize remaining V-1 vertices as unassigned
for (int u = 1; u < V; u++)
result[u] = -1; // no color is assigned to u
// A temporary array to store the available colors. True
// value of available[cr] would mean that the color cr is
// assigned to one of its adjacent vertices
bool available[V];
for (int cr = 0; cr < V; cr++)
available[cr] = false;
// Assign colors to remaining V-1 vertices
for (int u = 1; u < V; u++)
{
// Process all adjacent vertices and flag their colors
// as unavailable
list::iterator i;
for (i = adj[u].begin(); i != adj[u].end(); ++i)
if (result[*i] != -1)
available[result[*i]] = true;
// Find the first available color
int cr;
for (cr = 0; cr < V; cr++)
if (available[cr] == false)
break;
result[u] = cr; // Assign the found color
// Reset the values back to false for the next iteration
for (i = adj[u].begin(); i != adj[u].end(); ++i)
if (result[*i] != -1)
available[result[*i]] = false;
}
// print the result
for (int u = 0; u < V; u++)
cout << "Vertex " << u << " ---> Color "
<< result[u] << endl;
}
// Driver program to test above function
int main()
{
Graph g1(5);
g1.addEdge(0, 1);
g1.addEdge(0, 2);
g1.addEdge(1, 2);
g1.addEdge(1, 3);
g1.addEdge(2, 3);
g1.addEdge(3, 4);
cout << "Coloring of graph 1 \n";
g1.greedyColoring();
Graph g2(5);
g2.addEdge(0, 1);
g2.addEdge(0, 2);
g2.addEdge(1, 2);
g2.addEdge(1, 4);
g2.addEdge(2, 4);
g2.addEdge(4, 3);
cout << "\nColoring of graph 2 \n";
g2.greedyColoring();
return 0;
}
Java
// A Java program to implement greedy algorithm for graph coloring
import java.io.*;
import java.util.*;
import java.util.LinkedList;
// This class represents an undirected graph using adjacency list
class Graph
{
private int V; // No. of vertices
private LinkedList adj[]; //Adjacency List
//Constructor
Graph(int v)
{
V = v;
adj = new LinkedList[v];
for (int i=0; i it = adj[u].iterator() ;
while (it.hasNext())
{
int i = it.next();
if (result[i] != -1)
available[result[i]] = false;
}
// Find the first available color
int cr;
for (cr = 0; cr < V; cr++){
if (available[cr])
break;
}
result[u] = cr; // Assign the found color
// Reset the values back to true for the next iteration
Arrays.fill(available, true);
}
// print the result
for (int u = 0; u < V; u++)
System.out.println("Vertex " + u + " ---> Color "
+ result[u]);
}
// Driver method
public static void main(String args[])
{
Graph g1 = new Graph(5);
g1.addEdge(0, 1);
g1.addEdge(0, 2);
g1.addEdge(1, 2);
g1.addEdge(1, 3);
g1.addEdge(2, 3);
g1.addEdge(3, 4);
System.out.println("Coloring of graph 1");
g1.greedyColoring();
System.out.println();
Graph g2 = new Graph(5);
g2.addEdge(0, 1);
g2.addEdge(0, 2);
g2.addEdge(1, 2);
g2.addEdge(1, 4);
g2.addEdge(2, 4);
g2.addEdge(4, 3);
System.out.println("Coloring of graph 2 ");
g2.greedyColoring();
}
}
// This code is contributed by Aakash Hasija
Python3
# Python3 program to implement greedy
# algorithm for graph coloring
def addEdge(adj, v, w):
adj[v].append(w)
# Note: the graph is undirected
adj[w].append(v)
return adj
# Assigns colors (starting from 0) to all
# vertices and prints the assignment of colors
def greedyColoring(adj, V):
result = [-1] * V
# Assign the first color to first vertex
result[0] = 0;
# A temporary array to store the available colors.
# True value of available[cr] would mean that the
# color cr is assigned to one of its adjacent vertices
available = [False] * V
# Assign colors to remaining V-1 vertices
for u in range(1, V):
# Process all adjacent vertices and
# flag their colors as unavailable
for i in adj[u]:
if (result[i] != -1):
available[result[i]] = True
# Find the first available color
cr = 0
while cr < V:
if (available[cr] == False):
break
cr += 1
# Assign the found color
result[u] = cr
# Reset the values back to false
# for the next iteration
for i in adj[u]:
if (result[i] != -1):
available[result[i]] = False
# Pint the result
for u in range(V):
print("Vertex", u, " ---> Color", result[u])
# Driver Code
if __name__ == '__main__':
g1 = [[] for i in range(5)]
g1 = addEdge(g1, 0, 1)
g1 = addEdge(g1, 0, 2)
g1 = addEdge(g1, 1, 2)
g1 = addEdge(g1, 1, 3)
g1 = addEdge(g1, 2, 3)
g1 = addEdge(g1, 3, 4)
print("Coloring of graph 1 ")
greedyColoring(g1, 5)
g2 = [[] for i in range(5)]
g2 = addEdge(g2, 0, 1)
g2 = addEdge(g2, 0, 2)
g2 = addEdge(g2, 1, 2)
g2 = addEdge(g2, 1, 4)
g2 = addEdge(g2, 2, 4)
g2 = addEdge(g2, 4, 3)
print("\nColoring of graph 2")
greedyColoring(g2, 5)
# This code is contributed by mohit kumar 29
Javascript
输出:
Coloring of graph 1
Vertex 0 ---> Color 0
Vertex 1 ---> Color 1
Vertex 2 ---> Color 2
Vertex 3 ---> Color 0
Vertex 4 ---> Color 1
Coloring of graph 2
Vertex 0 ---> Color 0
Vertex 1 ---> Color 1
Vertex 2 ---> Color 2
Vertex 3 ---> Color 0
Vertex 4 ---> Color 3
时间复杂度:最坏情况下为 O(V^2 + E)。
基本算法分析
上述算法并不总是使用最小数量的颜色。此外,有时使用的颜色数量取决于处理顶点的顺序。例如,请考虑以下两个图。请注意,在右侧的图中,顶点 3 和 4 交换了。如果我们考虑左图中的顶点 0、1、2、3、4,我们可以使用 3 种颜色为图着色。但是如果我们考虑右图中的顶点 0、1、2、3、4,我们需要 4 种颜色。
所以选择顶点的顺序很重要。许多人提出了不同的方法来找到平均来说比基本算法更有效的排序。最常见的是 Welsh-Powell 算法,它按度数降序考虑顶点。
基本算法如何保证d+1的上限?
这里 d 是给定图中的最大度数。由于 d 是最大度数,因此一个顶点不能附加到 d 个以上的顶点。当我们为一个顶点着色时,它的相邻顶点最多可能已经使用了 d 种颜色。为了给这个顶点着色,我们需要选择相邻顶点不使用的最小编号颜色。如果颜色编号为 1, 2, ….,那么最小数字的值必须在 1 到 d+1 之间(请注意,相邻顶点已经选取了 d 个数字)。
这也可以用归纳法证明。请参阅此视频讲座以获取证明。
我们很快就会讨论一些关于色数和图形着色的有趣事实。
如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程和学生竞争性编程现场课程。