用图的邻接矩阵
a
a
a表示无向连通图
G
=
(
V
,
E
)
G = (V , E)
G=(V,E),若
(
i
,
j
)
(i , j)
(i,j)属于图
G
=
(
V
,
E
)
G = (V , E)
G=(V,E)的边集
E
E
E,则
a
[
i
]
[
j
]
=
1
a[i][j] = 1
a[i][j]=1,否则
a
[
i
]
[
j
]
=
0
a[i][j] = 0
a[i][j]=0,整数
1
1
1,
2
2
2,
?
\cdots
?,
m
m
m用来表示
m
m
m种不同颜色,顶点
i
i
i所着的颜色用
x
[
i
]
x[i]
x[i]表示,数组
x
[
1
:
n
]
x[1 : n]
x[1:n]是问题的解向量
问题的解空间可表示为一棵高度为
n
n
n的完全
m
m
m叉树,解空间树的第
i
(
0
≤
i
≤
n
?
1
)
i (0 \leq i \leq n - 1)
i(0≤i≤n?1)层中每个结点都有
m
m
m个儿子,每个儿子相应于
x
[
i
]
x[i]
x[i]的
m
m
m个可能的着色之一,第
n
n
n层结点均为叶结点
当
i
=
n
i = n
i=n时,算法搜索至叶结点,得到新的
m
m
m着色方案,当前找到的可
m
m
m着色方案数
s
u
m
sum
sum增
1
1
1
当
i
<
n
i < n
i<n时,当前扩展结点
Z
Z
Z是解空间中的内部结点,该结点有
m
m
m个儿子结点
x
[
i
]
x[i]
x[i],对当前扩展结点
Z
Z
Z的每个儿子结点,由约束函数检查其可行性,并以深度优先的方式递归地对可行子树搜索,或剪去不可行子树
时间复杂性
图
m
m
m可着色问题的解空间树中内结点个数是
∑
i
=
0
n
?
1
m
i
\displaystyle\sum\limits_{i = 0}^{n - 1}{m^{i}}
i=0∑n?1?mi,对于每个内结点,在最坏情况下,用约束函数检查当前扩展结点的每个儿子所对应的颜色的可用性需耗时
O
(
m
n
)
O(mn)
O(mn)
因此,回溯法总的时间耗费是
(
m
n
)
∑
i
=
0
n
?
1
m
i
=
n
×
m
(
m
n
?
1
)
/
(
m
?
1
)
=
O
(
n
m
n
)
(mn) \displaystyle\sum\limits_{i = 0}^{n - 1}{m^{i}} = n \times m (m^{n} - 1) / (m - 1) = O(n m^{n})
(mn)i=0∑n?1?mi=n×m(mn?1)/(m?1)=O(nmn)
Python实现
defcount_graph_coloring(graph, m):
n =len(graph)
colors =[-1]* n
count =0defis_valid(colors, vertex, color):# 约束函数: 检查给定顶点的着色是否满足约束条件(与相邻顶点的颜色不重复)for i inrange(n):if graph[vertex][i]and colors[i]== color:returnFalsereturnTruedefbacktrack(colors, vertex):nonlocal count
if vertex == n:
count +=1print(colors)returnfor color inrange(m):if is_valid(colors, vertex, color):
colors[vertex]= color
backtrack(colors, vertex +1)
colors[vertex]=-1
backtrack(colors,0)return count
graph =[[0,1,1,1],[1,0,1,0],[1,1,0,1],[1,0,1,0]]
m =3print('满足条件的着色方案如下:')
coloring_count = count_graph_coloring(graph, m)print(f'着色方案数: {coloring_count}')