2021-06-24

一、设计任务与目标

1、问题描述
图着色问题(Graph Coloring Problem, GCP) 又称着色问题,是最著名的NP-完全问题之一。道路着色问题(Road Coloring Problem)是图论中最著名的猜想之一。给定一个无向图G=(V, E),其中V为顶点集合,E为边集合,图着色问题即为将V分为K个颜色组,每个组形成一个独立集,即其中没有相邻的顶点。其优化版本是希望获得最小的K值。
2、设计目标
给定任意无向图,求出该图最少的着色数并给出着色方案。
二、设计思路
1、问题分析
地图着色问题是一个抽象的图形学问题,用程序实现对各个区域进行着色,并且相邻省所用的颜色不同,同时保证颜色的总数最少,那么就是如何将这些抽象的进行数据化。如何将程序所需要的功能模拟着色在计算机中编程实现。
由地图着色问题很容易想到图的着色问题,因此可以把地图抽象为无向图来解决地图的着色问题。其本质是图着色问题(Graph ColoringProblem, GCP) 又称着色问题,是最著名的NP完全问题之一。 对地图的抽象相当于对图的抽象,即以邻接矩阵来实现地图的区域相邻的描绘,而对地图的区域数即以图的顶点数来描绘。具体是将各个区域进行编号,然后利用无向图各个顶点之间的边来表示各省的相邻关系。地图着色问题与著名四色定理:四色定理是一个著名的数学定理:如果在平面上划出一些邻接的有限区域,那么可以用四种颜色来给这些区域染色,使得每两个邻接区域染的颜色都不一样:另一个通俗简洁的说法是:每个地图都可以用不多于四种颜色来染色,而且不会有两个邻接的区域颜色相同。这就是著名的四色定理,由四色定理可以想到只需要四种颜色就可以为一个区域的地图着上颜色,而且相邻区域的颜色不相同。
2、图的m-着色判定问题
程序采用回溯法来实现,回溯搜索是深度优先搜索(DFS) 的一种,回溯法有“通用的解题法”之称。用它可以系统的搜索一个问题的所有解或任一解。是一个既带有系统性又带有跳跃性的搜索算法。
在包含问题的所有解的解空间树中,按照深度优先搜索的策略,从根结点出发深度探索解空间树。当探索到某一结点时,要先判断该结点是否包含问题的解,如果包含,就从该结点出发继续探索下去,如果该结点不包含问题的解,则逐层向其祖先结点回溯。(其实回溯法就是对隐式图的深度优先搜索算法)。若用回溯法求问题的所有解时,要回溯到根,且根结点的所有可行的子树都要已被搜索遍才结束。而若使用回溯法求任一个解时,只要搜索到问题的一个解就可以结束。
(1) 给定无向连通图G和m种不同的颜色。用这些颜色为图G的各顶点着色,每个顶点着一种颜色,是否有一种着色法使G中任意相邻的2个顶点着不同颜色。
(2)输入
顶点数:5,颜色数:4
把所有情况都排出来,顶点1有4种颜色方案,顶点2、3、4、5都有4种颜色方案
我们假设一个实例来解决,平面图G=(V,E),V={V1,V2,V3,V4},|E|=4;用M=3种颜色去着色,分别把这三种颜色的序号标为1、2、3。先把所有节点颜色设置零,从根节点开始,对根节点用第一种颜色进行着色,第一个肯定着色有效,接下去接着对下一个节点着色,先用第一种颜色对其节点着色,然后判断这个节点与相邻节点是否相同,有相同颜色则判定为无效着色,继续用第二种颜色着色,直到着色有效为止,如果与相邻节点颜色没有相同,则判定为有效着色,继续下一节点着色。

(3)输出代码
#include
#include <bits/stdc++.h>
using namespace std;

#define MAX 100
int sum=0; //颜色方案数
int graph[MAX][MAX]; //顶点与顶点之间的联系
int color[MAX]; //每个顶点的颜色

bool Same(int n,int t)//判断t顶点与其他点是否有联系并且颜色相同
{
for(int i=1; i<=n; i++)
{
if((graph[t][i]==1) && (color[t]==color[i]))//有联系且相同返回
{
return false;
}
}
return true;
}
void BackTrack(int n,int m,int t)// t为顶点从1开始
{
if(t>n)
{
sum++; //颜色方案数+1
for(int i=1; i<=n; i++)// 输出方案
{
cout<<color[i]<<" ";
}
cout<<endl;
}
else
{
for(int i=1; i<=m; i++)//每个顶点从第一个颜色染色
{
color[t]=i; //t顶点染第i个颜色

        if(Same(n,t))//执行 true
        {
            BackTrack(n,m,t+1); //下一个顶点
        }
        color[t]=0;  //不执行 true,颜色重置,下一个循环,t顶点染下一个颜色
    }
}

}
int main()
{
int n,m; //顶点数 颜色数
cin>>n>>m;

//构建图G
int i,j;
while(scanf("%d%d",&i,&j) && (i!=0 || j!=0))
{
    graph[i][j]=1;
    graph[j][i]=1;
}
BackTrack(n,m,1);
cout<<sum;  //输出着色方案总数
return 0;

}

(4)结果

3、图的m-着色优化问题
若一个图最少需要m种颜色才能使图中任意相邻的2个顶点着不同颜色,则称这个数m为该图的色数。求一个图的最小色数m的问题称为m-着色优化问题。
(1)步骤
计算机中,图主要可以用两种方法表示:邻接矩阵和邻接链表。N个顶点的邻接矩阵是一个N*N的布尔矩阵,图中的每一个顶点都由一行或者一列来表示,如果从第i个顶点和第j个顶点之间有边连接,则矩阵第i行,第j列的元素等于1,如果没有边连接,则等于0.这就是图的邻接矩阵表示。
那么地图也可以抽象为一个图,其可以用邻接矩阵来进行模拟:对于每一个地图,我们可以把每一个区(区域或国家)看作一个点,而区与区之间的邻接关系看作点与点之间的连线。从而将地图抽象为-个图,然后就可以用邻接矩阵抽象。如下图:

第一个点添上第一个颜色黄色,color[1]=1;
第二个点添上第一个颜色黄色,color[2]=1,查找数组graph找已染色的点与点2的联系,graph[2][1]=1,说明点2与点1有联系,color[2]==color[1]说明颜色重复,第二个点添上第一个颜色黄色不行
第二个点添上第二个颜色红色color[2]=1,重复上述步骤…
以此类推,color[3]=1, color[3]=color[1]
color[3]=2, color[3]=color[2]
color[3]=3, …
以此类推…

(2)输出代码

#include
#include <bits/stdc++.h>
using namespace std;

#define MAX 100
int m=1;
int graph[MAX][MAX]; //点与点之间的联系
int color[MAX]; //每个点的颜色

void BackTrack(int n)
{
color[1]=1; //第一个点先染色
for(int t=2; t<=n; t++) //从第二个点开始染色
{
int f=0; //假设t点与染色点都有联系
for(int j=1; j<t; j++)//t点之前的都已经染色,查找t点与染色点是否有联系
{
if(graph[t][j]!=1) //有个点与t点无联系
{
f=1; //假设失败
color[t]=color[j]; //无联系则颜色可以相同
break;
}
}
if(f==0) //假设成功
{
color[t]=m+1; //都有联系只能染新颜色
m++;
}
}
for(int i=1;i<=n;i++)//输出各点颜色
{
cout<<color[i]<<" ";
}
cout<<endl;
}
int main()
{
int n; //n个点
cin>>n;

//构建图G
int i,j;
while(scanf("%d%d",&i,&j) && (i!=0 || j!=0)) //点与点之间的联系
{
    graph[i][j]=1;
    graph[j][i]=1;
}
BackTrack(n);
cout<<m; //最少颜色数
return 0;

}

(3)输出结果

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值