回溯、图论—— N色地图着色问题

1.问题描述

如果我们把地图上的每一个区域都退化成一个点,相邻的区域用连线连接起来,那么地图就变成了一个无向连通图,我们给地图着色就相当于给该无向连通图的每个点着色,要求有连线的点不能有相同的颜色。这就是典型的图的m着色问题。给定无向连通图G m种颜色,找出所有不同的着色方案,使相邻区域有不同的颜色。如以下例子:

     

该图一共有7个区域,分别是ABCDEFG,我们分别编号1-7,每一个区域用一个顶点表示,相邻的区域有连线,那么地图就转换成了一个无向连通图。

如果用3种颜色给该地图着色,那么该问题中每个结点所着的颜色都有3种选择,7个结点所着的颜色号组合是一个可行解,比如说:{1,2,3,2,1,2,3}。

2.算法设计

约束条件:

假设当前扩展结点处于解空间树的t层,那么1~t-1个结点的状态已经确定。接下来沿着扩展结点的第一个分支进行扩展,此时需要判断第t个结点的着色情况。第t个结点的着色要与前面t-1个结点种,与其中有边相连的结点的颜色要不一样,如果颜色一样,那么这个t结点就不能用这个颜色,要换一个颜色尝试。

比如说:

在前3个已经着色的结点中,4号结点和1号、3号结点有边相连,那么4号结点选择的颜色不可以和1、3号结点的颜色相同。

扩展结点沿着第一个分支扩展,判断约束条件,如果满足,则进入深一层继续搜索,如果不满足,则扩展生成的结点给剪掉,换下一个色号尝试。如果所有的色号都尝试完毕,该结点变成死结点,向上回溯到离其最近的活结点,继续搜索。搜索到叶子结点时,找到一种着色方案,搜索过程直到全部活结点都变成死结点为止。

3.源代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;

const int MAXX=111;//设定边界
int map[MAXX][MAXX]; //邻接矩阵存储图
int x[MAXX]; //解分量,记录色号
int sum=0; //记录有多少种方案
int n; //顶点个数
int m;//边的个数
int color_nums; //颜色数量

void createmap() //创建邻接矩阵
{
    int u; //顶点1
    int v; //顶点2
    cout << "请输入边的个数m:"<< endl;
    cin >> m;
    memset(map,0,sizeof(map));
    cout << "请输入有边相连的两个顶点u和v:"<< endl;
    for (int i=1;i<=m;i++)
    {
        cin >> u>>v;
        map[u][v]=1;
        map[v][u]=1;
    }
}

bool OK(int t) //判断色号是否相同的函数
{
    for(int j=1;j<t;j++) //判断现在扩展点t和前面t-1个顶点有没有相连的
    {
        if(map[t][j]) //如果相连
        {
            if(x[j]==x[t]) //且颜色一样
            {
                return false; //返回false,代表需要换个色号尝试
            }
        }
    }
    return true; //如果色号不一样就是true
}

void backtrack(int t) //回溯、递推函数
{
    if(t>n) //到达叶子节点
    {
        sum++; //方案个数
        cout << "第"<< sum << "种方案"<< endl;
        for (int i=1;i<=n;i++)
        {
            cout << x[i] << "    ";
        }
        cout << endl;
    }
    else
    {
        for (int i=1;i<=color_nums;i++) //尝试别的色号
        {
            x[t]=i;  //记录色号
            if(OK(t)) //如果色号没有撞
            {
                backtrack(t+1); //向下递推
            }
        }
    }
}


int main()
{
    cout << "请输入结点个数n:"<< endl;
    cin >> n;
    cout << "请输入颜色的数量:"<< endl;
    cin >> color_nums;
    cout << "请输入用邻接矩阵存储的图:"<< endl;
    createmap();
    backtrack(1);
    return 0;
}

4.测试结果

发布了57 篇原创文章 · 获赞 9 · 访问量 3609

猜你喜欢

转载自blog.csdn.net/Jayphone17/article/details/102963554