查找色号


13

令人惊讶的是,我们在图形着色方面还没有遇到任何挑战!

给定一个无向图,我们可以为每个顶点赋予一种颜色,使得没有两个相邻的顶点共享相同的颜色。实现此目的所需的最小数量的独特颜色χ被称为图形的色数

例如,以下显示使用最少数量的颜色的有效着色:

(在维基百科上找到)

因此,该图的色数为χ= 3

编写一个程序或函数,给定多个N <16的顶点(从1N),并给出一个边列表,确定一个图的色数。

只要输入未经过预处理,您就可以接收输入并以任何方便的格式产生输出。也就是说,您可以使用字符串或数组,可以在字符串中添加方便的定界符,也可以使用嵌套数组,但是无论您做什么,扁平化的结构都应包含与以下示例相同的数字(顺序相同)。

您可能不使用内置的图论相关功能(如Mathematica的ChromaticNumber)。

您可能会认为该图没有环(将顶点与其自身连接的边),因为那样会使该图不可着色。

这是代码高尔夫球,最短的答案(以字节为单位)获胜。

例子

您的程序必须至少在合理的时间内解决所有这些问题。(它必须正确解决所有输入,但是较大的输入可能需要更长的时间。)

为了缩短篇幅,在以下示例中,我在一个逗号分隔的列表中显示了边缘。如果愿意,您可以换行或使用一些方便的数组格式输入。

三角形(χ= 3)

3
1 2, 2 3, 1 3

6个顶点的“环”(χ= 2)

6
1 2, 2 3, 3 4, 4 5, 5 6, 6 1

5个顶点的“环”(χ= 3)

5
1 2, 2 3, 3 4, 4 5, 5 1

上面的示例图片(χ= 3)

6
1 2, 2 3, 3 4, 4 5, 5 6, 6 1, 1 3, 2 4, 3 5, 4 6, 5 1, 6 2

上面关于7个顶点的一般化(χ= 4)

7
1 2, 2 3, 3 4, 4 5, 5 6, 6 7, 7 1, 1 3, 2 4, 3 5, 4 6, 5 7, 6 1, 7 2

彼得森图(χ= 3)

10
1 2, 2 3, 3 4, 4 5, 5 1, 1 6, 2 7, 3 8, 4 9, 5 10, 6 8, 7 9, 8 10, 9 6, 10 7

具有5个顶点的完整图形,以及不连续的顶点(χ= 5)

6
1 2, 1 3, 1 4, 1 5, 2 3, 2 4, 2 5, 3 4, 3 5, 4 5

完整的8个顶点图(χ= 8)

8
1 2, 1 3, 1 4, 1 5, 1 6, 1 7, 1 8, 2 3, 2 4, 2 5, 2 6, 2 7, 2 8, 3 4, 3 5, 3 6, 3 7, 3 8, 4 5, 4 6, 4 7, 4 8, 5 6, 5 7, 5 8, 6 7, 6 8, 7 8

具有15个顶点的三角晶格(χ= 3)

15
1 2, 1 3, 2 3, 2 4, 2 5, 3 5, 3 6, 4 5, 5 6, 4 7, 4 8, 5 8, 5 9, 6 9, 6 10, 7 8, 8 9, 9 10, 7 11, 7 12, 8 12, 8 13, 9 13, 9 14, 10 14, 10 15, 11 12, 12 13, 13 14, 14 15

您能定义合理吗?1分钟?10个?
ThreeFx 2014年

@ThreeFx是的,十分钟是合理的。不是半天。我不想在限制上过于严格,因为那样的话,我需要再次在同一台(我的)计算机上测试所有内容。但是,假设它在一小时内在您的计算机上完成就可以了。
Martin Ender 2014年

Answers:


4

蟒2.7 - 122 109 111 109 108 103

f=lambda n,e,m=1:any(all(t*m//m**a%m!=t*m//m**b%m for(a,b)in e)for t in range(m**n))and m or f(n,e,m+1)

用法:

print f(5, [(1, 2), (2, 3), (3, 4), (4, 5), (5, 1)])

通过增加色数(m)进行蛮力检查所有可能的着色。可以将一种颜色描述为以m为底的数字。因此,可能的着色为0、1,...,m ^ n-1。

编辑:8个顶点的完整图形需要相当长的时间。但是我的笔记本电脑可以在大约10分钟内解决问题。其他测试用例仅需几秒钟。


编辑2:读取允许进行预处理,所以我让顶点的索引从0开始:将t * m // m ** x%m缩短为t // m ** a%m(-2)。分解lambda并将m放入函数参数(-11)


编辑3:预处理允许- >回T *米(4),简化//到/(-2)。


编辑4:谢谢xnor,删除任何(-2)中的方括号。


编辑5:不要取模m两次,只需将它们相减,然后再使用模(-1)。这也是相当不错的性能改进。在我的笔记本电脑上,所有测试用例合计大约需要25秒。


编辑6:递归调用,而不是while 1:和m + = 1(-5)。再次感谢,xnor。


不错的方法。一个简单的高尔夫:all([...])如果您将a,bin 包裹在括号内(由于间距,此处不包含任何字符),则可以卸下in的括号,以免将其all误认为其他参数。另外,我怀疑如果使用函数调用递归到下一个最高位m而不是使用while循环,则可以节省字符。
xnor 2014年

谢谢,递归方法虽然需要+2个字符。也适用于范围为(n + 1)的m。
雅库布2014年

我使用anyand/or技巧优化了递归方法,然后节省了一些字符:f=lambda n,e,m=1:any(all(t*m//m**a%m!=t*m//m**b%m for(a,b)in e)for t in range(m**n))and m or f(n,e,m+1)
xnor 2014年

2

爪哇- 241 218

int k,j,c;int f(int n,int[]e){for(k=1;k<=n;k++)for(long p=0;p<x(n);p++){for(j=0,c=0;j<e.length;c=p%x(e[j])/x(e[j]-1)==p%x(e[j+1])/x(e[j+1]-1)?1:c,j+=2);if(c<1)return k;}return 0;}int x(int a){return(int)Math.pow(k,a);}

给定约束,最明显的方法是蛮力。只需遍历每个色数k,然后将每种颜色分配给每个顶点即可。如果没有邻居是同一颜色,则您有您的电话号码。如果没有,继续前进。

对于测试用例来说,这花费了最长的时间χ = 8(完整的图形在这里很烂),但仍不到15秒(好的,最新编辑大约是100秒)。

输入是顶点的数量n,以及e[]以与OP逗号分隔值相同的顺序给出的边顶点数组。

带换行符:

int k,j,c;
int f(int n,int[]e){
    for(k=1;k<=n;k++)
        for(long p=0;p<x(n);p++){
            for(j=0,c=0;
                j<e.length;
                c=p%x(e[j])/x(e[j]-1)==p%x(e[j+1])/x(e[j+1]-1)?1:c,
                j+=2);
            if(c<1)return k;
        }
    return 0;
}
int x(int a){return(int)Math.pow(k,a);}

哦,这假设输入是某种可着色的图形。如果边缘从v1到v1循环,或者没有顶点,则无法着色并且将输出0。它仍然适用于没有边缘的图形χ=1,等等。


2

Python 3-162

使用相同的蛮力方法,但是使用itertools库来希望更快地生成组合。在我相当普通的机器上,用不到1分钟的时间解决了完整的8张图形。

import itertools as I
def c(n,v):
 for i in range(1,n+1):
  for p in I.product(range(i),repeat=n):
   if(0==len([x for x in v if(p[x[0]]==p[x[1]])])):return i

完整的8图情况的用法示例:

print(c(8,[x for x in I.combinations(range(8), 2)]))

1

Haskell,163个字节

p x=f(length x)(transpose x)1
f a[b,c]d|or$map(\x->and$g x(h b)(h c))(sequence$replicate a[1..d])=d|0<1=f a b c(d+1)
g a=zipWith(\x y->a!!x/=a!!y)
h=map(flip(-)1)

用法如下:

p [[1, 2],[2, 3],[3, 1]]

基本暴力手段。检查所有可能的颜色组合是否有效。除了在这里我无话可说之外,我很高兴听到任何进一步缩短此提示的提示;)


我想说,减少顶点并对其进行转置算作“预处理”。我想到的“任何方便的格式”是,您可以从平面列表,嵌套列表,字符串,带有方便定界符的字符串等中进行选择……但是扁平化的结构应与挑战中指定的相同。
Martin Ender 2014年

@MartinBüttner好吧,我将其更改
ThreeFx 2014年

@ThreeFx all id与相同andany id与相同,or并且any id$map f list与just相同any f list。同样,您可以使用以下方法来做一些事情g:您可以将其重新定义为g a=(and.).zipWith(\x y->a!!x/=a!!y),使其成为infix,更改输入顺序以替换(\x->g x b c)g b c,甚至使其完全无点并内联。其中一些无法协同工作,因此请尝试所有方法并选择最佳的一种:)
自豪的haskeller 2014年

1
@MartinBüttner我认为它是固定的,可以保证maaaaany字节的成本。:D
ThreeFx 2014年

1
在输入中没有顶点数量的情况下,如何解决第7个示例?
Martin Ender 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.