地图着色问题:核心原理与 C++ 代码实现

一、核心问题:一句话秒懂

地图着色的核心需求很简单:给地图上的所有区域着色,确保相邻区域(有公共边界,非点接触)颜色不同,同时使用最少的颜色

关键结论(四色定理):无论平面地图的区域如何划分,最多只需 4 种颜色就能满足 “相邻区域不同色” 的要求,这为我们的算法实现提供了明确的颜色数量上限。

二、问题简化:地图 → 图论模型转化

复杂的地图无法直接用代码处理,我们需要将其转化为计算机能理解的 “图论模型”,规则如下:

  • 地图上的每个区域 → 图中的一个 “顶点”(用数字 0、1、2... 标识);
  • 两个区域相邻 → 图中对应的两个顶点之间连一条 “边”(用邻接矩阵标记);
  • 着色要求 → 有边连接的两个顶点(相邻区域)必须使用不同颜色。

简言之:地图着色问题 = 图的顶点着色问题(相邻顶点颜色不同)。

三、核心算法:回溯法(试错法)

对于中小规模地图(10-20 个区域),回溯法是最直观、易实现的算法,核心思路类似 “走迷宫试路”:

  1. 按顺序遍历每个顶点(区域);
  2. 为当前顶点尝试分配 1-4 种颜色(符合四色定理);
  3. 检查颜色是否合法(不与相邻顶点的颜色重复);
  4. 若合法,继续处理下一个顶点;若不合法,换一种颜色尝试;
  5. 若所有颜色都尝试失败,回溯到上一个顶点,换颜色重新尝试;
  6. 直到所有顶点都着色完成,记录最少使用的颜色数。

四、精简 C++ 代码实现(可直接运行)

cpp

运行

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

const int MAX_REGIONS = 10;  // 最多支持 10 个区域
int adj_matrix[MAX_REGIONS][MAX_REGIONS] = {0};  // 邻接矩阵:1=相邻,0=不相邻
int region_color[MAX_REGIONS] = {0};  // 记录每个区域的颜色(0=未着色)
int min_colors = MAX_REGIONS;  // 最少颜色数(初始设为最大区域数)
int region_count;  // 实际区域总数

// 检查当前区域(cur)使用颜色(color)是否合法
bool is_color_valid(int cur, int color) {
    for (int i = 0; i < region_count; i++) {
        // 若相邻区域(adj_matrix[cur][i]=1)已使用该颜色,不合法
        if (adj_matrix[cur][i] == 1 && region_color[i] == color) {
            return false;
        }
    }
    return true;
}

// 回溯函数:当前处理第 cur 个区域
void backtrack_color(int cur) {
    // 所有区域都着色完成,更新最少颜色数
    if (cur == region_count) {
        int used_colors = 0;
        for (int c : region_color) {
            used_colors = max(used_colors, c);
        }
        min_colors = min(min_colors, used_colors);
        return;
    }

    // 尝试 1-4 种颜色(符合四色定理)
    for (int c = 1; c <= 4; c++) {
        if (is_color_valid(cur, c)) {
            region_color[cur] = c;  // 分配颜色
            backtrack_color(cur + 1);  // 处理下一个区域
            region_color[cur] = 0;  // 回溯:撤销当前颜色分配
        }
    }
}

int main() {
    // 示例:4 个区域(0-3)的相邻关系(可根据实际地图修改)
    region_count = 4;
    // 区域 0 与 1、2 相邻
    adj_matrix[0][1] = adj_matrix[1][0] = 1;
    adj_matrix[0][2] = adj_matrix[2][0] = 1;
    // 区域 1 与 2、3 相邻
    adj_matrix[1][2] = adj_matrix[2][1] = 1;
    adj_matrix[1][3] = adj_matrix[3][1] = 1;
    // 区域 2 与 3 相邻
    adj_matrix[2][3] = adj_matrix[3][2] = 1;

    // 开始回溯着色
    backtrack_color(0);

    // 输出结果
    cout << "最少需要的颜色数:" << min_colors << endl;
    cout << "各区域的颜色分配(0=未着色,1-4=颜色编号):";
    for (int i = 0; i < region_count; i++) {
        cout << region_color[i] << " ";
    }
    cout << endl;

    return 0;
}

五、代码使用说明(小白也能会)

  1. 修改区域数量:将 region_count 设为你的地图实际区域数(≤10);
  2. 设置相邻关系:通过 adj_matrix[i][j] = 1 标记区域 i 和 j 相邻(注意双向设置,如 adj_matrix[0][1] = 1 同时要 adj_matrix[1][0] = 1);
  3. 运行代码:直接编译运行,会输出 “最少颜色数” 和 “各区域颜色分配”;
  4. 扩展场景:若需要支持更多区域,修改 MAX_REGIONS 的值即可(如改为 20 支持 20 个区域)。

六、核心原理总结

  1. 地图着色的本质是图的顶点着色,核心约束是 “相邻顶点不同色”;
  2. 四色定理为算法提供了颜色数量上限(最多 4 种),无需无意义尝试更多颜色;
  3. 回溯法通过 “尝试 - 验证 - 回溯” 的逻辑,能找到最少颜色的最优解,适合中小规模场景;
  4. 邻接矩阵是图论问题的常用表示方式,简洁直观,便于代码实现。

该代码可直接用于小规模地图着色场景(如小区分区、学校楼层区域、简单省份地图等),如需优化大规模场景(如全国地图),可在此基础上引入剪枝、贪心算法等优化手段

以下是一个基于C语言和EasyX图形库的可视化地图着色代码,可以直观地展示地图着色的过程。 ```c #include <graphics.h> #include <conio.h> #include <stdio.h> #include <stdlib.h> #include <time.h> #define MAX_VERTEX_NUM 100 // 最大顶点数 #define MAX_COLOR_NUM 10 // 最大颜色数 struct Graph { int vertex[MAX_VERTEX_NUM][2]; // 顶点坐标 int edge[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; // 邻接矩阵 int vertex_num; // 顶点数 }; struct Vertex { int id; // 顶点编号 int x, y; // 顶点坐标 int color; // 顶点颜色 }; Graph map; // 地图 Vertex vertex[MAX_VERTEX_NUM]; // 顶点 int color_num = 0; // 颜色数 int color[MAX_COLOR_NUM]; // 颜色 // 初始化地图 void init_map() { map.vertex_num = 5; map.vertex[0][0] = 100; map.vertex[0][1] = 100; map.vertex[1][0] = 300; map.vertex[1][1] = 100; map.vertex[2][0] = 300; map.vertex[2][1] = 200; map.vertex[3][0] = 200; map.vertex[3][1] = 300; map.vertex[4][0] = 100; map.vertex[4][1] = 200; for (int i = 0; i < map.vertex_num; i++) { for (int j = 0; j < map.vertex_num; j++) { map.edge[i][j] = 0; } } map.edge[0][1] = map.edge[1][0] = 1; map.edge[1][2] = map.edge[2][1] = 1; map.edge[2][3] = map.edge[3][2] = 1; map.edge[3][4] = map.edge[4][3] = 1; map.edge[4][0] = map.edge[0][4] = 1; } // 初始化顶点 void init_vertex() { for (int i = 0; i < map.vertex_num; i++) { vertex[i].id = i; vertex[i].x = map.vertex[i][0]; vertex[i].y = map.vertex[i][1]; vertex[i].color = 0; } } // 初始化颜色 void init_color() { color_num = 4; color[0] = RGB(255, 0, 0); // 红色 color[1] = RGB(0, 255, 0); // 绿色 color[2] = RGB(0, 0, 255); // 蓝色 color[3] = RGB(255, 255, 0); // 黄色 } // 绘制地图 void draw_map() { setbkcolor(WHITE); cleardevice(); setlinestyle(PS_SOLID, 2); setlinecolor(BLACK); for (int i = 0; i < map.vertex_num; i++) { for (int j = i + 1; j < map.vertex_num; j++) { if (map.edge[i][j]) { line(map.vertex[i][0], map.vertex[i][1], map.vertex[j][0], map.vertex[j][1]); } } } for (int i = 0; i < map.vertex_num; i++) { setfillcolor(vertex[i].color); fillcircle(vertex[i].x, vertex[i].y, 20); settextcolor(BLACK); char str[10]; sprintf_s(str, "%d", i); outtextxy(vertex[i].x - 5, vertex[i].y - 7, str); } } // 判断顶点是否可以染色 bool can_color(int v, int c) { for (int i = 0; i < map.vertex_num; i++) { if (map.edge[v][i] && vertex[i].color == c) { return false; } } return true; } // 对顶点进行染色 bool color_vertex(int v) { if (v == map.vertex_num) { // 所有顶点都染色了 return true; } for (int c = 0; c < color_num; c++) { // 枚举颜色 if (can_color(v, c)) { // 如果可以染色 vertex[v].color = color[c]; draw_map(); // 绘制地图 delay(500); if (color_vertex(v + 1)) { // 继续染色下一个顶点 return true; } vertex[v].color = 0; // 回溯 } } return false; } int main() { init_map(); init_vertex(); init_color(); initgraph(400, 400); color_vertex(0); getch(); closegraph(); return 0; } ``` 该程序使用了图形库EasyX来绘制地图和顶点,并使用了延迟函数delay来控制绘制速度。在程序运行时,可以看到地图逐渐被染色,直到所有顶点都被染色为止。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值