Найти хроматическое число

13

Удивительно, но у нас еще не было проблем с раскраской графиков!

Учитывая неориентированный граф, мы можем дать каждой вершине такой цвет, чтобы никакие две смежные вершины не имели одинаковый цвет. Наименьшее число χ различных цветов, необходимое для достижения этого, называется хроматическим числом графа.

Например, ниже показано допустимое окрашивание с использованием минимального количества цветов:

(Найдено в Википедии)

Таким образом, хроматическое число этого графа χ = 3 .

Напишите программу или функцию, которая, учитывая количество вершин N <16 (которые пронумерованы от 1 до N ) и список ребер, определяет хроматическое число графа.

Вы можете получать входные данные и создавать выходные данные в любом удобном формате, если входные данные не были предварительно обработаны. То есть вы можете использовать строку или массив, добавить в строку удобные разделители или использовать вложенный массив, но что бы вы ни делали, выровненная структура должна содержать те же числа, что и примеры ниже (в том же порядке).

Вы не можете использовать встроенные функции, связанные с теорией графов (например, 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
@ThreeFx да, 10 минут разумно. пол дня нет. Я не хочу быть слишком строгим на пределе, потому что тогда мне нужно снова протестировать все на той же (моей) машине. но, скажем, если это завершится в течение часа на вашей машине, это нормально.
Мартин Эндер

Ответы:

4

Python 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. Таким образом, возможные окраски 0, 1, ..., m ^ n-1.

редактировать: полный граф из 8 вершин занимает довольно много времени. Но мой ноутбук решает это за 10 минут. Другие тестовые случаи занимают всего несколько секунд.


правка 2: прочитайте, что предварительная обработка разрешена, поэтому я позволяю индексу вершин начинаться с 0: сокращает t * m // m ** x% m до t // m ** a% m (-2). Растворите лямбду и введите m в функциональные параметры (-11)


редактировать 3: предварительная обработка не разрешена -> обратно к t * m (+4), упрощено // до / (-2).


редактировать 4: удалить квадратные скобки в любом (-2), спасибо xnor.


редактировать 5: вместо того, чтобы взять по модулю m дважды, просто вычтите их и затем используйте по модулю (-1). Это тоже значительное улучшение производительности. Все тесты вместе занимают около 25 секунд на моем ноутбуке.


edit 6: рекурсивный вызов вместо while 1: и m + = 1 (-5). Еще раз спасибо, xnor.

Jakube
источник
Хороший метод. Простой гольф: вы можете убрать скобки, all([...])если заключите скобки в скобки a,b(которые не стоят здесь символов из-за пробелов), чтобы они allне принимали их за дополнительные аргументы. Кроме того, я подозреваю, что вы можете сохранить символы, если вы выполняете процедуру с вызовом функции до следующего наивысшего уровня, mа не с помощью цикла while.
xnor
Спасибо, рекурсивный подход требует +2 символа. A для m в диапазоне (n + 1) также подходит.
Якуб
Я оптимизировал Рекурсивный подход немного с anyи and/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
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и т. Д.

Geobits
источник
2

Питон 3 - 162

Использует тот же подход грубой силы, но использует библиотеку itertools для, как мы надеемся, более быстрой генерации комбинации. Решает полный 8-граф за <1 мин на моей довольно обычной машине.

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)]))
RT
источник
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]]

Основной подход грубой силы. Проверьте все возможные цветовые комбинации, если они действительны. Больше нечего сказать, кроме того, что я рад услышать любые советы по сокращению этого еще дальше;)

ThreeFx
источник
Я бы сказал, что уменьшение вершин и их транспонирование считается «предварительной обработкой». Что касается «любого удобного формата», то я имел в виду, что вы можете выбирать из плоского списка, вложенного списка, строки, строки с удобными разделителями и т. Д., Но уплощенная структура должна быть такой же, как указано в задании.
Мартин Эндер
@ MartinBüttner Хорошо, я изменю это
ThreeFx
@ThreeFx all id- это то же самое and, any idто же самое, что orи any id$map f listпросто any f list. Кроме того , вы можете сделать несколько вещей с g: вы можете переопределить его как g a=(and.).zipWith(\x y->a!!x/=a!!y), сделать его инфиксным, изменить порядок ввода , чтобы заменить (\x->g x b c)с g b cили даже сделать его полностью Точки бесплатно и коридорным его. некоторые из них не работают вместе, поэтому попробуйте их все и выберите лучший :)
гордый haskeller
1
@ MartinBüttner Я думаю, что это фиксировано, к стоимости байтов maaaaany. : D
ThreeFx
1
Как вы решаете 7-й пример без количества вершин на входе?
Мартин Эндер