【问题标题】:graph coloring with exactly k colours用恰好 k 种颜色进行图形着色
【发布时间】:2018-06-02 21:44:33
【问题描述】:

考虑一个有 V 个顶点和 E 个边的图 G(V,E)。我们想用 K 种颜色给顶点图上色。

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

我们如何实现这个问题?

【问题讨论】:

    标签: algorithm graph graph-algorithm graph-coloring


    【解决方案1】:

    首先让我们注意 2 假设:

    1. 如果 |V| = k。
    2. 如果我们可以用小于 k 的颜色和 |v| 为图形着色> k 那么它也可以使用完全 k 的颜色 - 我们可以将重复的颜色与我们尚未使用的颜色进行切换。

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

    让每个颜色分配编号 [1,2,...,k] - 让我们用 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
        adjs <- current.getAdj()
        colors = new Set
        for each adjs as adj:
            colors.add(adj.colors)
        for i = 1 to k:
            if i not in colors: //found lowest color avilable
                 current.color <- C[i]
                 break
        if current.color == 0 return false // cannot assign any color
        Queue.insert(adjs)
    

    【讨论】:

    • 这并不总是有效,因为一般问题是 NP 完全问题。您的算法将在颜色用完时中止,但它需要回溯以修复先前的决定以使其正确。
    【解决方案2】:

    维基百科中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;
    }
    

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-07-17
      • 1970-01-01
      • 2020-08-27
      • 1970-01-01
      • 2015-07-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多