图形着色与k颜色

时间:2018-06-02 21:44:33

标签: algorithm graph graph-algorithm graph-coloring

考虑具有V顶点和E边的图G(V,E)。我们想要用正好的K颜色对顶点图进行着色。

着色图意味着以两个相邻顶点不应具有相同颜色的方式为每个节点指定颜色。

我们如何实施这个问题?

2 个答案:

答案 0 :(得分:2)

首先让我们注意2个假设:

  1. 如果| V | k。
  2. 如果我们可以用小于k的颜色和| v |为图上色> k,那么也可能恰好有k种颜色-我们可以将重复的颜色切换为尚未使用的颜色。

我们可以使用贪婪算法来解决这个问题。

让每种颜色分配数字[1,2,...,k]-让u用Ci代表颜色i。从任意节点v1开始并为其分配C1。现在让我们在图表上运行BSF,为每个节点选择在其调整节点中不存在的最小颜色-如果另一个节点没有颜色,则忽略它们。如果d(v)> k且他的所有调整都使用不同的颜色,则返回false。

伪代码:

// v.color init as 0 for all V
Queue <- new Queue(V1)
While Queue not empty:
    current <- Queue.pop
    if (current.color != 0 )
         continue
    adj <- v1.getAdj()
    min = 0
    for each adj:
         min = min(min, adj.color) 
    current.color <- C[min + 1]
    Queue.insert(adj)

答案 1 :(得分:0)

维基百科上graph coloring algorithms上的条目指出了一个问题,即图形是否允许以正确的 k 着色(如果通过边连接,则没有两个相同颜色的顶点)颜色是NP完全的。

蛮力算法是您所希望的最好的算法(除非您有其他约束,例如图是二分图或平面图)。暴力破解算法如下:

#include <iostream>
#include <string>

using namespace std;

// describes a partial answer to the problem
struct Coloring {
    static const int maxV = 5;

    // only the first k colors count
    int colors[maxV];

    void show(int k) const {
        cout << "{";
        for (int i=0; i<k; i++) {
            cout << colors[i] << " ";
        }                                  
        cout << "}" << endl;
    }     
};

// A graph
struct Graph {
    int availableColors;
    int numV;
    bool edges[Coloring::maxV][Coloring::maxV];

    void handleAnswer(Coloring &s) const {
        cout << "EUREKA: ";
        s.show(numV);
    }

    // checks if the k-th vertex avoids being same-color as neighbors
    bool isPartialAnswer(const Coloring &s, int k) const {
        cout << std::string(k, ' ') << "testing: ";
        s.show(k);
        for (int i=0; i<k; i++) {
            for (int j=0; j<i; j++) {
                if ((edges[i][j] || edges[j][i]) 
                    && (s.colors[i] == s.colors[j])) {
                    cout << std::string(k, ' ') << " .. but " 
                        << i << " & " << j << " have same color" << endl;
                    return false;
                }
            }
        }
        return true;
    }

    bool isAnswer(const Coloring &s, int k) const {
        return k == numV;
    }                        
};

void paint(Coloring &s, int k, const Graph &c) {
    // initializes level
    cout << std::string(k, ' ') << "entering k=" << k << ": ";
    s.show(k); 

    // test with each possible color for the next vertex
    for (int i=0; i<c.availableColors; i++) {
        // modify current partial answer
        s.colors[k] = i;
        // is it still a partial answer?
        if (c.isPartialAnswer(s, k+1)) {
            // is it a full answer?
            if (c.isAnswer(s, k+1)) {
                c.handleAnswer(s);
            } else {
                // continue down this road
                paint(s, k+1, c);
            }
        }
    }
    // backtrack: we have exhausted all continuations of this coloring
    cout << std::string(k, ' ') << "closing k=" << k << endl;
}

int main() {
    Graph c = {4, 4, 
        {{0, 1, 0, 0, 0},
        {0, 0, 1, 1, 0},
        {0, 0, 0, 1, 0},
        {0, 0, 0, 0, 0},
        {0, 0, 0, 0, 0},}};

    Coloring s;
    paint(s, 0, c);
    return 0;
}

免责声明:这是回溯算法的典型示例,其设计目的是为了清楚起见,而不是为了提高性能或可扩展性。