给定图的顶点的k-着色计算(k-​​1) - 着色

时间:2014-10-26 23:58:52

标签: algorithm optimization recursion np-complete graph-coloring

众所周知,图的着色顶点是NP完全的。 众所周知,有效的贪婪算法可以得到近似的解决方案。 为什么不使用这些随机贪婪算法来计算k颜色的颜色,然后使用一些较慢的算法来减少k?

在我的情况下,我知道足够颜色图G的最小颜色数量 - 我们称之为K.我还设法实现了SL算法,它给了我(K + 2)颜色。一种颜色仅用于为一个顶点着色,因此我设法通过手动重新着色其他一些节点来删除它。因此,我有(K + 1)颜色,并且想编写一个能够将K(或更确切地说是K + 1)减少1的算法。

我试图手动完成 - 我发现一种颜色用于由相同颜色着色的最小数量的顶点,并将此颜色的使用减少到3.我必须重新着色3个节点。

一个想法是进行3次递归调用 - 每个颜色很深的节点一次。让我们分析递归函数对节点v必须做什么。它必须检查除了v的颜色和我们想要删除的颜色之外的每种颜色。因此,对于每种颜色c,它应该将v的颜色设置为c,并对每个节点进行递归调用,该节点是v的邻居并且具有颜色c。检查完所有颜色后,我们应检索v的旧颜色并重新设置。还有一个优化可能不是试图将v的颜色更改为超过其邻居x的颜色(因为递归树太深) - 但是对于太小的x,它可能根本无法改变颜色。 / p>

另一个想法是检查颜色可以改变的节点(不是我们想要删除的颜色),这样就不会碰到邻居的颜色。并进行递归调用以更改其他节点的颜色,直到我们要删除的一种颜色将重新着色。

这是我对第一个算法的实现,该算法旨在用于n< 90但似乎没有结束(执行500分钟):

#include<stdio.h>
#include<assert.h>
#include<vector>
using namespace std;

vector<int> graph[99];
int hash[10009], color[99];
const int colors = 9, color_to_change = 7;

void change_color(int v)
{
    int tmp = color[v], count;
    for(int i = 1; i <= colors; ++i)
    {
        count = 0;
        for(int j = 0; j < graph[v].size(); ++j)
            count += color[graph[v][j]] == i;
        if(!count)
        {
            color[v] = i;
            return;
        }
        if(count < 4 && i != color_to_change && i != color[v])
        {
            color[v] = i;
            for(int j = 0; j < graph[v].size(); ++j)
                if(color[graph[v][j]] == i)
                    change_color(graph[v][j]);
        }
    }
    color[v] = tmp;
}

int main()
{
    int n, m, a, b, max = 0, j = -1;

    scanf("%d%d", &n, &m);
    while(m--)
    {
        scanf("%d%d", &a, &b);
        assert(a != b);
        if(hash[a*100+b] || hash[b*100+a])
            continue;
        assert(a*100+b < 10000 && b*100+a < 10000);
        hash[a*100+b] = hash[b*100+a] = 1;
        graph[a].push_back(b);
        graph[b].push_back(a);
    }
    for(int i = 1; i <= n; ++i)
        scanf("%d", &color[i]);
    for(int i = 1; i <= n; ++i)
        if(color[i] == color_to_change)
            change_color(i);
    for(int i = 1; i <= n; ++i)
        printf("%d ", color[i]);
    return 0;
}

任何想法如何让它更快?

1 个答案:

答案 0 :(得分:2)

我只是简单地查看了代码,并阅读了你的解释,但似乎你进入了一个无限循环,在邻居之间来回切换。你需要在每个节点中存储一个标志,以指出它当前正在重新着色,并且只能递归到那些当前没有被重新加工的邻居。

然而 - 这个算法在最坏的情况下看起来像是指数 - 而且我很确定有些情况下,K色图不能在不改变大部分图形的情况下重新成为K-1图形,甚至如果颜色K的节点数仅为1。

这是一个简单拓扑图。很明显它可以是两种颜色(R,G),我们有三种颜色版本使用(R,G,B)。正确重新着色的唯一方法是更改​​大约1/2节点颜色,最后是下面的其他版本之一。 ()表示颜色B的单个节点,[]表示需要重新着色的部分。

3 colour version  :  R-G-R-G-R-G-(B)-R-G-R-G-R-G-R
2 colour version 1: [R-G-R-G-R-G- R]-G-R-G-R-G-R-G
2 colour version 2:  G-R-G-R-G-R-[G -R-G-R-G-R-G-R]

这意味着您(潜在指数)搜索的最小深度可能超过节点数量的1/2。这个可能会杀死合理的性能时间(或者可能不会取决于我猜测的图形的拓扑结构。)