0
点赞
收藏
分享

微信扫一扫

【回溯算法】图的m着色问题

眸晓 2022-04-14 阅读 93
c++算法dfs

【问题描述】

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

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

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

输入

第一行是顶点的个数n(2≤n≤10),颜色数m(1≤m≤n)。

接下来是顶点之间的相互关系:a b

表示a和b相邻。当a,b同时为0时表示输入结束。

输出

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

最后一行是着色方案总数。

【算法分析】

对m种颜色编号为1,2,…,m,由于每个顶点可从m种颜色中选择一种颜色着色,如果无向连通图G=(V, E)的顶点数为n,则解空间的大小为m的n次方种,解空间是非常庞大的,它是一棵m叉树。

当n=3,m=3时的解空间树:

 图的m着色问题的约束函数是相邻的两个顶点需要着不同的颜色,但是没有限界函数

假设无向连通图G=(V, E)的邻接矩阵为a,如果顶点i和j之间有边,则a[i][j]=1,否则a[i][j]=0。

设问题的解向量为X (x1, x2 , …, xm) ,其中xi∈{1, 2, …, m},表示顶点i所着的颜色是x[i],

即解空间的每个结点都有m个儿子。

【代码部分】

//图的m着色问题回溯算法的数据结构

#define NUM 100
int n;				//图的顶点数量
int m;			//可用颜色数量
int a[NUM][NUM];	//图的邻接矩阵
int x[NUM];		//当前的解向量
int sum ;			//已经找到的可m着色的方案数量
//图的m着色问题回溯算法的实现

//形参t是回溯的深度,从1开始
void BackTrack(int t )
{
  int i;
  //到达叶子结点,获得一个着色方案
  if( t > n )
  {
    sum ++ ;
    for(i=1; i<=n ;i++)
      printf("%d ",x[i]);
    printf("\n");
  }
  else 
    //搜索当前扩展结点的m个孩子
    for(i=1; i<=m; i++ )
    {
      x[t] = i;
      if( Same(t) ) BackTrack(t+1);
      x[t] = 0;
    }
}

 

//检查相邻结点的着色是否一样的约束函数

//形参t是回溯的深度
bool Same(int t)
{
  int i;
  for(i=1; i<=n; i++ )
    if( (a[t][i] == 1) && (x[i] == x[t]))
      return false;
  return true;
}

 

#include <iostream>
#include<bits/stdc++.h>
#define N 100
#define INF 0x3f3f3f3f
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define rep(i,a,n) for(int i=a;i<=n;i++)
typedef long long ll;
using namespace std;
#define NUM 100
int n;//图的顶点数量
int m;//可用颜色数量
int a[NUM][NUM];//图的邻接矩阵
int x[NUM];//当前的解向量
int sum ;//已经找到的可m着色的方案数量
bool Same(int t)//约束函数
{
    int i;
    for(i=1;i<=n;i++)
    {
        if((a[t][i]==1)&&(x[i]==x[t]))//这一行,相邻的
            return false;
    }
    return true;
}
void Backtrack(int t)//搜索t层结点
{
    int i;
    if(t>n)
    {
        sum++;
        for(i=1;i<=n;i++)
        {
            cout<<x[i]<<" ";
        }
        cout<<endl;
    }
    else
    {
        for(i=1;i<=m;i++)
        {
            x[t]=i;//颜色值
            if(Same(t))Backtrack(t+1);
            x[t]=0;//恢复
        }
    }
}

int main()
{
    cin>>n>>m;
    int i,j;
    while(cin>>i>>j&&i&&j)
    {
        a[i][j]=a[j][i]=1;
    }
   Backtrack(1);
   cout<<sum<<endl;
}

举报

相关推荐

0 条评论