1. 程式人生 > 實用技巧 >回溯法之圖的m著色問題

回溯法之圖的m著色問題

回溯法之圖的m著色問題


1. 問題描述

​ 給定無向連通圖\(G\)\(m\)種不同的顏色。用這些顏色為圖\(G\)的各個頂點著色,每個頂點著一種顏色。是否有一種著色發使\(G\)中每條邊的2個頂點著不同顏色。這個問題是圖的\(m\)可著色判定問題。若一個圖最少需要\(m\)種顏色才能使圖中每條邊連結的2個頂點著不同顏色,則稱這個數\(m\)為該圖的色數。求一個圖的色數\(m\)的問題稱為圖的\(m\)可著色優化問題。

2.問題分析

​ 本問題只探討對於給定的\(m\),求解其可\(m\)著色的方案數
解向量:\((x_1, x_2, ..., x_n)\)表示頂點\(i\)所著顏色\(x_i\)


可行性約束函式:頂點\(i\)與已著色的相鄰頂點顏色不重複

3.程式碼求解

​ 使用變數:

/**
 * n    國家數
 * m    可用顏色數
 * a    圖的鄰接矩陣
 * x    當前解
 * sum  著色方案數
 **/
int n = MAX;
int 0m;
int a[MAX + 1][MAX + 1] = {
    {0, 0, 0, 0, 0, 0},
    {0, 0, 1, 1, 1, 0},
    {0, 1, 0, 1, 1, 1},
    {0, 1, 1, 0, 1, 0},
    {0, 1, 1, 1, 0, 1},
    {0, 0, 1, 0, 1, 0}
};
int x[MAX + 1];
long sum = 0;

​ 核心程式碼:

// ok約束函式
// 要求a[k][j] == 1即倆頂點相鄰
// x[j] == x[k]即二者的顏色重複
// 當二者都滿足時,即該節點不符合剪枝函式,剪去
int ok(int k) {
    for (int j = 1; j < k; j++)
        if (a[k][j] && (x[j] == x[k]))
            return 0;
    return 1;
}

// t > n代表一種著色方案通過
// 通過遍歷m,對各個結點設定不同的顏色
// 然後通過剪枝函式,只留下相鄰頂點顏色不重複的分支,繼續遞迴求解
void BackTrack(int t) {
    if (t > n)
        sum++;
    else
        for (int i = 1; i <= m; i++) {
            x[t] = i;
            if (ok(t))
                BackTrack(t + 1);
        }
}

4. 完整程式碼

/**
 * 回溯法之圖的n著色問題
 **/
#include <stdio.h>
#include <stdlib.h>

#define MAX 5

/**
 * n    國家數
 * m    可用顏色數
 * a    圖的鄰接矩陣
 * x    當前解
 * sum  著色方案數
 **/
int n = MAX;
int m;
int a[MAX + 1][MAX + 1] = {
    {0, 0, 0, 0, 0, 0},
    {0, 0, 1, 1, 1, 0},
    {0, 1, 0, 1, 1, 1},
    {0, 1, 1, 0, 1, 0},
    {0, 1, 1, 1, 0, 1},
    {0, 0, 1, 0, 1, 0}
};
int x[MAX + 1];
long sum = 0;

// ok約束函式
// 要求a[k][j] == 1即倆頂點相鄰
// x[j] == x[k]即二者的顏色重複
// 當二者都滿足時,即該節點不符合剪枝函式,剪去
int ok(int k) {
    for (int j = 1; j < k; j++)
        if (a[k][j] && (x[j] == x[k]))
            return 0;
    return 1;
}

// t > n代表一種著色方案通過
// 通過遍歷m,對各個結點設定不同的顏色
// 然後通過剪枝函式,只留下相鄰頂點顏色不重複的分支,繼續遞迴求解
void BackTrack(int t) {
    if (t > n)
        sum++;
    else
        for (int i = 1; i <= m; i++) {
            x[t] = i;
            if (ok(t))
                BackTrack(t + 1);
        }
}

void main() {
    m = 3;
    BackTrack(1);
    printf("%d\n", sum);

    system("pause");
}