PTA-图k-着色问题

一、问题

图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即可)。
PTA-图k-着色问题_第1张图片

二、代码

/*
    描述: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
#include 
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
    // {
    //     for(int i=1;i<=node_nums;i++)
    //     {
    //         cout<
    //     }
    //     cout<
    // }

    return 0;
}

你可能感兴趣的:(SCNU_PTA,算法,数据结构,c++)