1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7

# теория · шаг 2 из 7

Раскраска графа: почему три цвета сложнее двух

Коротко

Правильная раскраска - назначение вершинам цветов так, чтобы соседи не совпадали; хроматическое число χ(G) - наименьшее число цветов, которого хватает. Два цвета проверяются за O(V + E) (это двудольность из прошлого урока), а уже для трёх задача NP-полна: быстрого алгоритма не известно, и найти его значило бы решить главную открытую проблему информатики. Поэтому на практике красят ЖАДНО: перебирают вершины в каком-то порядке и дают каждой наименьший цвет, не занятый её соседями. Жадность никогда не тратит больше Δ + 1 цветов, где Δ - максимальная степень, но ОПТИМУМА НЕ ГАРАНТИРУЕТ: результат зависит от порядка, и на специально построенном графе она промахивается сколь угодно сильно (иногда, впрочем, попадает в оптимум - как в разборе ниже).

Если ты знаешь про хроматическое число, помнишь оценку жадной раскраски Δ + 1 и понимаешь, почему три цвета - трудная задача, а два - лёгкая, листай до «Теперь сам».

Как думаешь, где проходит граница трудности

Проверить, хватает ли ДВУХ цветов, мы научились за один обход. Прежде чем читать дальше, прикинь: как проверить, хватает ли ТРЁХ? Есть ли столь же простой критерий вроде «нет циклов такой-то длины»? Подсказка: если бы он был, о нём бы знали - и задача не входила бы в список классических трудных.

На что это похоже

Расписание экзаменов. Экзамены, на которые записан один и тот же студент, нельзя ставить в одно время - это ребро в графе. Цвет - время проведения. Минимальное число цветов - минимальное число слотов, за которое можно провести сессию. Легко проверить, хватит ли двух дней. А вот вопрос «хватит ли трёх» внезапно становится переборным: никакого простого признака у него нет.

Механизм: жадная раскраска и её граница

def greedy_coloring(order):
    color = [-1] * V
    for v in order:                       # порядок - параметр!
        used = {color[u] for u in adj[v] if color[u] != -1}
        c = 0
        while c in used:                  # наименьший свободный цвет
            c += 1
        color[v] = c
    return color

Почему цветов не больше Δ + 1: у вершины не больше Δ соседей, значит они занимают не больше Δ цветов, и среди цветов 0..Δ хотя бы один свободен. Цена - O(V + E).

Что известно про сами числа:

χ(G) = 1   ⇔ рёбер нет вовсе
χ(G) <= 2  ⇔ граф двудолен (проверяется за O(V + E))
χ(G) <= 3  - NP-полная задача уже для планарных графов
χ(G) <= Δ + 1 всегда (жадная раскраска)
χ(G) <= Δ   для связного графа, кроме полного графа и нечётного цикла (теорема Брукса)
χ(G) >= размер наибольшей клики (полного подграфа)

Порядок перебора решает многое. Популярные эвристики: по убыванию степени (Welsh-Powell); smallest-last - многократно снимать вершину НАИМЕНЬШЕЙ степени, складывая снятые в стек, а потом красить в обратном порядке; DSATUR - на каждом шаге брать вершину с наибольшим числом РАЗНЫХ цветов среди соседей. На практике они дают близкие к оптимуму ответы, но гарантии оптимальности не дают ни одна.

Правило

Правильная раскраска - соседи разных цветов; χ(G) - минимальное число цветов. χ <= 2 проверяется за O(V + E) (двудольность), проверка χ <= 3 NP-полна. Жадная раскраска даёт не больше Δ + 1 цветов за O(V + E), но зависит от порядка и оптимальной не гарантирует. Нижняя граница - размер наибольшей клики; по теореме Брукса связному графу хватает Δ цветов, кроме полного графа и нечётного цикла.

Разбор: жадность зависит от порядка

Классический плохой случай - «корона»: двудольный граф с долями {a₁...a_k} и {b₁...b_k}, где a_i соединена со всеми b_j, КРОМЕ b_i. Он двудольный, значит двух цветов хватает заведомо. Возьмём k = 3 и проследим два порядка.

Порядок по долям (a₁, a₂, a₃, b₁, b₂, b₃): все a попарно не соседи → все получают цвет 0. Каждая b видит только вершины a (цвет 0) → все получают цвет 1. Итого два цвета, оптимум.

Порядок вперемешку (a₁, b₁, a₂, b₂, a₃, b₃). Выпишем соседей: a₁ дружит с b₂ и b₃, a₂ - с b₁ и b₃, a₃ - с b₁ и b₂.

a₁ → покрашенных соседей нет                     → цвет 0
b₁ → соседи a₂, a₃ ещё белые                       → цвет 0   (b₁ и a₁ НЕ соседи)
a₂ → сосед b₁ цвета 0                            → цвет 1
b₂ → сосед a₁ цвета 0 (a₃ ещё не покрашена)      → цвет 1
a₃ → соседи b₁ (0) и b₂ (1)                      → цвет 2
b₃ → соседи a₁ (0) и a₂ (1)                      → цвет 2

Итого три цвета вместо двух - и всё из-за порядка.

На больших k эта конструкция даёт k цветов вместо двух: разрыв между жадностью и оптимумом неограничен. Это не мелкий недостаток, а причина, по которой раскраску не считают решённой задачей.

Разбор: почему два легко, а три трудно

Полезно понять, ГДЕ ломается рассуждение при переходе от двух цветов к трём.

С двумя цветами выбора нет: как только покрашена одна вершина, цвета всех остальных в её компоненте определены однозначно - каждый сосед обязан быть противоположным. Алгоритм просто распространяет единственно возможное решение и либо доходит до конца, либо натыкается на противоречие. Никакого перебора.

С тремя цветами выбор появляется: покрасив вершину в цвет 0, её соседу можно дать 1 ИЛИ 2. Каждое такое решение влияет на дальнейшее, и отката может потребоваться сколь угодно много. Именно эта свобода и делает задачу переборной: известно, что 3-раскраска NP-полна, причём даже для планарных графов (для которых, к слову, четырёх цветов хватает всегда - об этом следующий урок).

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

Что ломается без этого

Первое: считать, что жадная раскраска даёт хроматическое число - она даёт лишь верхнюю оценку, и на специально построенных графах промахивается в разы. Второе: ждать, что «хороший» порядок решит проблему - эвристики помогают в среднем, но и у DSATUR есть плохие входы. Третье: путать Δ + 1 с точным ответом: у длинного пути Δ = 2, а хватает двух цветов, а не трёх. Четвёртое: забывать про нижнюю границу - если в графе есть клика на k вершинах, меньше k цветов не бывает никогда, и это первый способ доказать, что решение оптимально. Пятое: пытаться свести задачу к раскраске и удивляться, что «алгоритм долго работает»: точная раскраска - экспоненциальный перебор, и надо сразу выбирать между точностью и временем.

Зачем это в работе

Самое известное применение - распределение регистров в компиляторах: вершина это переменная, ребро означает «эти две живут одновременно, значит не могут занимать один регистр», цвет - регистр. Если цветов не хватает, часть переменных «выплёскивают» в память; современные компиляторы используют именно эвристики раскраски. Дальше: назначение частот передатчикам (соседние вышки не должны работать на одной частоте), составление расписаний (экзамены, смены, переговорки), планирование задач с конфликтами за ресурс, разбиение тестов на группы, которые можно гонять параллельно. Общее во всех: «конфликтующие сущности - в разные слоты», и сразу же общий вывод - точного решения ждать не стоит, а хорошая эвристика с внятной верхней границей чаще всего и есть ответ.

Теперь сам

Граф - «колесо»: цикл 1-2-3-4-5-1 и центр 6, соединённый со всеми пятью. Сколько цветов нужно? Сколько даст жадная раскраска в порядке 6, 1, 2, 3, 4, 5?

Ответ. Сначала оптимум. Центр соединён со всеми, значит его цвет не может совпасть ни с одним другим - один цвет уходит на него. Остальные пять образуют цикл нечётной длины, а такому циклу двух цветов не хватает (это критерий из прошлого урока), нужно три. Центру нужен цвет, отличный от всех цветов цикла, значит всего 3 + 1 = 4. Меньше нельзя: три цвета цикл израсходует полностью, и центру, который видит все пять его вершин, не останется ничего. Значит χ = 4. Теперь жадность в порядке 6, 1, 2, 3, 4, 5: 6 → цвет 0. 1 → сосед 6 цвета 0 → цвет 1. 2 → соседи 6 (0) и 1 (1) → цвет 2. 3 → соседи 6 (0) и 2 (2) → цвет 1. 4 → соседи 6 (0) и 3 (1) → цвет 2. 5 → соседи 6 (0), 4 (2) и 1 (1) → цвет 3. Жадность потратила четыре цвета - здесь она попала в оптимум. Проверь себя: максимальная степень Δ = 5 (у центра), значит граница Δ + 1 = 6, и реальный результат оказался заметно лучше границы - так обычно и бывает, но гарантии нет.

Главное

Правильная раскраска - соседи разных цветов; χ(G) - минимальное число цветов. Граница простоты проходит между двумя и тремя: χ <= 2 равносильно двудольности и проверяется обходом за O(V + E), а проверка χ <= 3 NP-полна - и причина видна прямо в алгоритме: с двумя цветами выбора нет (цвет соседа определён однозначно), с тремя появляется развилка, и решение становится переборным. На практике красят жадно: перебирают вершины и дают каждой наименьший цвет, свободный у соседей; это O(V + E) и не больше Δ + 1 цветов, потому что Δ соседей не могут занять Δ+1 цвет. Но результат зависит от ПОРЯДКА, и на специально построенном двудольном графе жадность даёт k цветов вместо двух - разрыв неограничен. Полезные ориентиры: нижняя граница - размер наибольшей клики; теорема Брукса даёт Δ цветов для связного графа, кроме полного графа и нечётного цикла; эвристики порядка (по убыванию степени, DSATUR) улучшают результат, но гарантий не дают. Раскраска - это распределение регистров, частот, слотов расписания: там, где конфликтующие сущности нельзя ставить вместе.

Комментарии

Пока нет комментариев. Будь первым!

Оставить комментарий

Комментарий появится после проверки. Email не публикуется. Войти, чтобы не вводить имя каждый раз.