回溯法 图着色问题

问题:

给定 无向连通图G=(V,E) 和 c种不同的颜色,用这些颜色为图G的各顶点着色,每个顶点着一种颜色。如果一个图最少需要c种颜色才能使图中每条边连接的2个顶点着不同颜色,则称c为该图的色数。
著名的 四色定理 就是指每个平面地图都可以只用四种颜色来染色,而且没有两个邻接的区域颜色相同。

求:给定图的顶点v,顶点间的边邻接关系graph[][],颜色的数量c,一共有多少种着色方法?

这里写图片描述

对于上面这图,颜色数量为4,顶点数为5,求得的解答树如下:

这里写图片描述
ps:解答树只给出部分

分析:

当cur = 3时,即填第3个顶点的颜色时,(1,2,1,*,)表示第1个顶点着第1中颜色,第2个顶点着第2个颜色,第3个顶点着第1个颜色,但是根据邻接表,顶点1和3是相邻的,因此此节点的子树没有解,因此用剪枝函数剪去

(1,2,2,*,)表示第1个顶点着第1个颜色,第2个顶点着第2个颜色,第3个顶点着第1个颜色,但是根据邻接表,顶点1和2是相邻的,因此此节点的子树没有解,因此用剪枝函数剪去

(1,2,3,1,*)表示第1个顶点着第1个颜色,第2个顶点着第2个颜色,第3个顶点着第3个颜色,第4个顶点着第1个颜色,顶点1和顶点4不是相邻的,因此可以都使用第1个个颜色,因此按照该节点的子树进行下一层的dfs

最终得出:(1,2,3,1,*)下的解有(1,2,3,1,3),(1,2,3,1,4),(1,2,3,1,5)

…..以此类推

分析时的规律:

  1. cur:代表当前层,当前行,cur+1表示去到下一层或下一行;
  2. for中的i:代表当前列,i++表示横移到右一列或是右一兄弟节点
  3. 要分清用什么填什么,(用i填cur)图着色问题这里就是用颜色填顶点位置

代码实现

#include<iostream>
using namespace std;

int v,e,graph[100][100];//v顶点数, e边数, graph图的邻接矩阵 
int c,color[100];//c颜色数  color当前边的颜色 
int sum = 0;//着色方法的数目 

//判断当前位置的颜色是否和相邻位置颜色重复 
bool ok(int cur){
    for(int i=1; i<=v; i++){
        if(graph[cur][i] && color[cur] == color[i]){//如果坐标(cur,i)相邻 且 cur的颜色和i的颜色相同 
            return false; 
        }
    }
    return true;
}

void backtrace(int cur){
    if(cur > v){
        sum++;
    } else {
        for(int i=1; i<=c; i++){//分别为cur位置尝试第i中颜色 
            color[cur] = i;//表示cur位置图上第i种颜色 
            if(ok(cur)){
                backtrace(cur+1);
            }
            color[cur] = 0;
        }
    }
}

int main(){
    cout << "输入顶点数和颜色数量:" ;
    cin >> v >> c;
    cout << endl;
    //输入邻接矩阵 
    for(int i=1; i<=v; i++){
        for(int j=1; j<=v; j++){
            cin >> graph[i][j];
        }
    }
    backtrace(1);
    cout << sum;
}

样例输入:
5 4
0 1 1 1 0
1 0 1 1 1
1 1 0 1 0
1 1 1 0 1
0 1 0 1 0

样例输出:
48

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值