问题描述:给定无向连通图G和m种不同的颜色。用这些颜色为图G的各顶点着色,每个顶点着一种颜色,是否有一种着色法使G中任意相邻的2个顶点着不同颜色?
回溯算法
/**
* 图的着色问题 - 回溯算法实现
*/
class GraphColoring {
/**
* @param {number[][]} graph - 图的邻接矩阵表示
* @param {number} m - 可用的颜色数量
*/
constructor(graph, m) {
this.graph = graph;
this.numVertices = graph.length;
this.m = m; // 可用颜色的数量
this.colors = new Array(this.numVertices).fill(0); // 存储每个顶点的颜色,0表示未着色
}
/**
* 检查为顶点 v 分配颜色 c 是否安全(合法)
* @param {number} v - 当前顶点的索引
* @param {number} c - 尝试分配的颜色 (1 to m)
* @returns {boolean} - 是否可以分配
*/
isSafe(v, c) {
for (let i = 0; i < this.numVertices; i++) {
// 检查 v 和 i 是否是邻居,以及邻居 i 是否已经使用了颜色 c
if (this.graph[v][i] === 1 && this.colors[i] === c) {
return false;
}
}
return true;
}
/**
* 递归的工具函数,用于解决着色问题
* @param {number} v - 当前正在处理的顶点索引
* @returns {boolean} - 是否找到了一个解
*/
solveColoringUtil(v) {
// --- Base Case: 基本情况 ---
// 如果所有顶点都已经被成功着色,说明找到了一个解
if (v === this.numVertices) {
return true;
}
// --- Recursive Step: 递归步骤 ---
// 尝试为顶点 v 分配每一种颜色
for (let c = 1; c <= this.m; c++) {
// 检查为顶点 v 分配颜色 c 是否安全
if (this.isSafe(v, c)) {
// 分配颜色
this.colors[v] = c;
// 递归地为下一个顶点着色
if (this.solveColoringUtil(v + 1)) {
return true; // 如果后续的顶点都成功着色,返回 true
}
// --- Backtrack: 回溯 ---
// 如果为 v 分配颜色 c 无法导向一个解,则撤销这次选择
this.colors[v] = 0;
}
}
// 如果尝试了所有颜色都无法为顶点 v 找到一个合法的方案,则返回 false
return false;
}
/**
* 主函数,启动回溯算法
*/
solve() {
// 从顶点 0 开始尝试着色
if (this.solveColoringUtil(0)) {
console.log(`成功找到一个使用 ${this.m} 种颜色的着色方案:`);
this.printSolution();
return true;
} else {
console.log(`无法使用 ${this.m} 种颜色为该图找到着色方案。`);
return false;
}
}
/**
* 打印解决方案
*/
printSolution() {
const colorMap = ["", "红色", "绿色", "蓝色", "黄色", "紫色", "橙色"]; // 方便阅读
const solution = this.colors.map((color, index) =>
`顶点 ${index}: ${colorMap[color] || `颜色${color}`}`
);
console.log(solution.join('\n'));
}
}
// --- 示例 ---
// 假设有4个顶点,其连接关系如下:
// 0 -- 1
// | \ |
// | \ |
// 2 -- 3
const graphMatrix = [
[0, 1, 1, 1], // 顶点0 连接到 1, 2, 3
[1, 0, 1, 0], // 顶点1 连接到 0, 2
[1, 1, 0, 1], // 顶点2 连接到 0, 1, 3
[1, 0, 1, 0], // 顶点3 连接到 0, 2
];
const m_colors = 3; // 尝试使用3种颜色
console.log("--- 尝试使用3种颜色 ---");
const coloringProblem1 = new GraphColoring(graphMatrix, m_colors);
coloringProblem1.solve();
console.log("\n" + "-".repeat(30) + "\n");
// 尝试一个不可能的方案
const m_colors_insufficient = 2; // 尝试使用2种颜色
console.log("--- 尝试使用2种颜色 ---");
const coloringProblem2 = new GraphColoring(graphMatrix, m_colors_insufficient);
coloringProblem2.solve();