问题:给定无向连通图G=(V,E),求最小的整数m,用m种颜色对图G的顶点着色,使得任意的两个相邻顶点着色不同
比如对于上面这个图,显然最小的颜色有2种 :1 3 4一种颜色,2,5一种颜色,那么对于贪心算法和回溯算法,我们要怎么来求解这个问题呢?首先来说一下贪心算法:
贪心算法
对于贪心算法,其中一种显然的贪心策略就是用一种颜色,尽可能多的为多个顶点去上色,例如对于上图 我们就有以下的步骤
① 对1上色k1并且flag = true,对2上色k1,发现1的颜色和2一样,取消上色并且flag = false,继续对34上色k1 ,满足条件,上色k1,对5继续上色k1,3 4结点和他相邻且颜色一样,取消上色并且flag = false
②取第二种颜色k2(k++并且flag = true,继续从1开始判断,发现1有颜色了,continue,判断2,对2上色,符合条件,判断34有色,continue,判断5,对5上色,ok,全部颜色上色完毕
实现贪心算法
#include<bits/stdc++.h>
using namespace std;
int edge[100][100],color[100];
//贪心算法
int drawcolor(int n){
int k = 0;
bool flag = true;
while(flag){
k++;//取下一种颜色
flag = false;//假设全部上色了
for(int i = 1;i<=n;i++){
if(color[i]!=0) continue;//已经上色了
color[i]=k;
for(int j = 1;j<=n;j++)
{
if(edge[i][j]==1&&color[j]==k)
{
color[i]=0;//取消上色
flag = true;
break;
}
//邻边颜色相同
}
}
}
return k;
}
int main()
{
int n,n2,x,y;//边数
cin>>n>>n2;
for(int i = 0;i<n2;i++)
{
cin>>x>>y;
edge[x][y] = 1;
edge[y][x] = 1;
}
cout<<"贪心算法得到有结果"<<drawcolor(n)<<"种";
}
但是贪心算法得到的结果依然不是最佳的解法,比如对于下图:
这是一个二部图,我们使用以上贪心算法得到的结果就不会是最佳结果,我们会得到4钟颜色,但是其实最佳结果是2钟(实际上二部图都只需要2种颜色就可以完成上色,奇偶不同色即可),所以贪心算法得到结果并不是最好的,这里我们就需要使用回溯法
回溯法
首先给出m种颜色,要求对n个顶点上色,比如下面这张图
我们可以用空间树,画出下面这样的图,先对A上色k1,然后尝试对B上色,直到可以为止,然后继续对C,D,E
如果有子树都不行的情况,就回溯到上个上个结点,如8的子树都不行,就回溯到7,对7继续画出空间树
代码实现:
#include<bits/stdc++.h>
using namespace std;
int edge[100][100],color[100];
//回溯算法
bool panduan(int i,int n){
for(int j = 1;j<=n;j++){
if(edge[i][j]==1&&color[j]==color[i])
return false;
}
return true;
}
void drawcolor(int n,int m){
memset(color,0,sizeof(0));
for(int i = 1;i<=n;){
color[i]++;//取下一种颜色
while(color[i]<=m&&!panduan(i,n))
color[i]++;
if (color[i]>m) {
color[i] =0;
i--;//回溯
}
else if(i<n) i++;//开始尝试为下一个上色
else {
//i==n
for(int k = 1;k<=n;k++)
cout<<"节点"<<k<<"的颜色是"<<color[k]<<endl;
return ;
}
}
}
int main()
{
int n1,n2,m,x,y;
cin>>n1>>n2>>m;
for(int i = 0;i<n2;i++)
{
cin>>x>>y;
edge[x][y] = 1;
edge[y][x] = 1;
}
drawcolor(n1,m);
}
对于上图样例
对于上图二部图样例 发现确实只需要两种颜色就可以完成对二部图的涂色问题
做题感悟:发现对于需要回溯法的题目,他们都有相似的模板 ,很多问题我们只需要套用下面模板就可以完成啦
for(int i = 0;i<=n;){
//
//code段
if(不符合的条件)回溯
else if(满足条件) i++
else {
//i= n
输出or返回
}
}