一、问题
图k-着色问题是一个著名的NP完全问题。给定无向图G=(V,E)和正整数k,问可否用k种颜色为V中的每个结点分配一种颜色,使得不会有两个相邻结点具有同一种颜色?
该问题的一个具体实例可能会有多个解(一个解就是一种合法的着色方案),要求计算全部解的数目。
输入格式:
输入的第一行包含三个整数N(1≤N≤20)、M(0≤M≤N(N−1)/2)和K(1≤K≤N),分别是无向图的结点数、边数和可用颜色数。
结点从1到N编号,颜色从1到K编号。随后M行,每行给出一条边的两个端点的编号。题目保证给定的无向图是简单图(即不存在自环和多重边)。
输出格式:
输出一行表示全部解的数目(无解时输出0即可)。
二、代码
/*
描述:k着色问题
日期:221102
思路:
1、回溯思想:
是一种选优搜索法,又称为试探法,按选优条件向前搜索,以达到目标。
但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,
这种走不通就退回再走的技术为回溯法。可以简单理解为,每个结点都分为k叉,
一步一步往下搜,当出现不符合条件的结点时,进行剪枝,然后回溯到上一个结点,接着访问。
2、本题思路:
(1)使用递归,递归函数传递的参数是当前节点的节点编号(v),递归函数的意义是,当前节点(v)
被成功上色,若是成功上色,那么会更新相应的color数组的值,否则什么也不做,return即可
(2)递归的出口是:
1)当节点编号已经大于原图的节点数目的时候(v==node_nums+1),说明已经把全部节点都
上色过了,说明完成了任务,那么return即可,且在return之前要将res_nums++,将color数组
保存到choices的二维数组中,保存好不同方案的颜色的选择
2)并不是所有的选择方案都能够完成任务,完不成任务的时候,也即在v节点找不到任何一个
可行的颜色给v上色,这种情况什么也不用管,因为给v上色的过程是一个对颜色选择for循环
的过程,在这个循环中会对每一种情况(不同颜色配v节点)做判断是否可行,若是不可行,
不上色就行,不需要多余的操作
(3)回溯法的使用:对v的下一个节点(v+1)递归之前会先对v节点上色(不必担心是否冲突,
因为已经判断过if_safe()了),然后使用递归函数对v+1节点递归rec_color(v+1),到目前为止
是常规的递归,回溯只有一行代码,就是说,递归结束之后,会把v节点上的色退回,color[v]=0;
不然的话,在对颜色选择for循环中,只能给v上第一个不冲突的颜色,也就满足于此了。如是不归零,
那么就只能返回一种结果。
*/
#include<iostream>
#include <vector>
using namespace std;
int node_nums,path_nums,color_nums;
vector<vector<int>>graph(21,vector<int>(21,0));
vector<vector<int>>color_choices;
vector<int>color(21,0);
int res_nums=0;
//用于判断v节点上color_chice色是否可行
bool is_safe(int v,int color_chice)
{
for(int i=1;i<=node_nums;i++)
//遍历v节点的那一行邻接矩阵
{
if(graph[v][i]==1&&color[i]==color_chice)
//当v节点与i节点相邻且i节点的着色颜色号同样也是color_chice的时候,即为有冲突
return false;
}
return true;
}
void rec_color(int v)
{
if(v==node_nums+1)
//当节点为最后一个节点时,找到一个方案
{
color_choices.push_back(color);//记录颜色方案选择
res_nums++;//方案数量加1
return;
}
for(int c=1;c<=color_nums;c++)
{
if(is_safe(v,c))
{
color[v]=c;//给v节点上色
rec_color(v+1);//对v上本次颜色的情况,递归,这样可以看到v带有本次颜色的所有后续结果
//对v的颜色归零回溯,这样才不至于只保存第一个合格的颜色,最后只返回一种颜色了
//见上方思路-2-(3)
color[v]=0;
}
}
}
int main()
{
//输入数据
cin>>node_nums>>path_nums>>color_nums;
while(path_nums--)
{
int a,b;
cin>>a>>b;
graph[a][b]=1;
graph[b][a]=1;
}
//获取结果
rec_color(1);
//输出结果
cout<<res_nums<<endl;
//输出选择方案
// for(int j=0;j<res_nums;j++)
// {
// for(int i=1;i<=node_nums;i++)
// {
// cout<<color_choices[j][i];
// }
// cout<<endl;
// }
return 0;
}