• 回溯法(四)——图的m着色问题


    1 题目描述

      给定无向连通图G=(V, E)m种不同的颜色,用这些颜色为图G的各顶点着色,每个顶点着一种颜色。是否有一种着色法使G中相邻的两个顶点有不同的颜色?

      这个问题是图的m可着色判定问题。若一个图最少需要m种颜色才能使图中每条边连接的两个顶点着不同颜色,则称这个数m为该图的色数。求一个图的色数m的问题称为图的m可着色优化问题。

      编程计算:给定图G=(V, E)m种不同的颜色,找出所有不同的着色法和着色总数。

    2 输入

      第一行是顶点的个数n(2≤n≤10),颜色数m(1≤m≤n);
      接下来是顶点之间的相互关系:a b,表示a和b相邻。当a,b同时为0时表示输入结束。

    3 输出

      输出所有的着色方案,表示某个顶点涂某种颜色号,每个数字的后面有一个空格。最后一行是着色方案总数。

    4 样例输入

    5 4
    1 3
    1 2
    1 4
    2 3
    2 4
    2 5
    3 4
    4 5
    0 0
    

    5 样例输出

    1 2 3 4 1 
    1 2 3 4 3 
    1 2 4 3 1 
    1 2 4 3 4 
    1 3 2 4 1 
    1 3 2 4 2 
    1 3 4 2 1 
    1 3 4 2 4 
    1 4 2 3 1 
    1 4 2 3 2 
    1 4 3 2 1 
    1 4 3 2 3 
    2 1 3 4 2 
    2 1 3 4 3 
    2 1 4 3 2 
    2 1 4 3 4 
    2 3 1 4 1 
    2 3 1 4 2 
    2 3 4 1 2 
    2 3 4 1 4 
    2 4 1 3 1 
    2 4 1 3 2 
    2 4 3 1 2 
    2 4 3 1 3 
    3 1 2 4 2 
    3 1 2 4 3 
    3 1 4 2 3 
    3 1 4 2 4 
    3 2 1 4 1 
    3 2 1 4 3 
    3 2 4 1 3 
    3 2 4 1 4 
    3 4 1 2 1 
    3 4 1 2 3 
    3 4 2 1 2 
    3 4 2 1 3 
    4 1 2 3 2 
    4 1 2 3 4 
    4 1 3 2 3 
    4 1 3 2 4 
    4 2 1 3 1 
    4 2 1 3 4 
    4 2 3 1 3 
    4 2 3 1 4 
    4 3 1 2 1 
    4 3 1 2 4 
    4 3 2 1 2 
    4 3 2 1 4 
    Total=48
    

    6 求解思路

      使用回溯法,具体步骤是将cur=1传入backtrack(),即从第一个开始涂色。

      涂的时候从颜色1开始到m,每当涂上一个色,要用ok(cur)判断第cur个点是否可以涂这个色,不可以的话就不再往下涂了,改试另一个颜色,可以的话就继续……执行完这个for循环就回溯。

      当cur>n的时候即前n个点都涂完了,然后输出结果并cou++计数。

    7 C++版本代码如下

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    
    using namespace std;
    
    int n, m;
    int a = 1, b = 1;
    int cou = 0;
    // 邻接矩阵
    int graph[20][20];
    // 着色表
    int color[20];
    
    // 判断是否可以着色
    bool ok(int c)
    {
        for(int k=1;k<=n;k++)
        {
            if(graph[c][k]&&color[c]==color[k])
            {
                return false;
            }
        }
        return true;
    }
    
    void backtrack(int cur)
    {
        if(cur>n)
        {
            for(int i=1;i<=n;i++)
            {
                printf("%d ",color[i]);
            }
            cou++;
            printf("
    ");
        }
        else
        {
            for(int i=1;i<=m;i++)
            {
                color[cur]=i;
                if(ok(cur))
                {
                    backtrack(cur+1);
                }
                color[cur]=0;
            }
        }
    }
    
    int main()
    {
        memset(graph, 0, sizeof(graph));
        memset(color, 0, sizeof(color));
        scanf("%d %d", &n, &m);
        while(scanf("%d %d", &a, &b) != EOF && a != 0 && b != 0)
        {
            graph[a][b] = 1;
            graph[b][a] = 1;
        }
        backtrack(1);
        printf("Total = %d", cou);
        return 0;
    }
    
  • 相关阅读:
    常用分页插件
    sessionStorage二种存值取值的方法
    $(this).index()与$(obj).index(this)的区别
    每次移1px的无缝轮播图
    为什么全局变量在赋值之前调用会报错
    Number()、parseInt()和parseFloat()的区别
    JSON.parse()与JSON.stringify()
    HDU
    出现负数的01背包问题
    HDU
  • 原文地址:https://www.cnblogs.com/flyingrun/p/13489952.html
Copyright © 2020-2023  润新知