Так, друзья, ну давайте продолжим разбираться с графами! Какие у нас еще есть хорошие задачи? Вот классическая задача, которую хочется разобрать. Мне кажется, что это действительно очень полезно. Давайте так: вот есть граф какой-то. Давайте как-нибудь обозначим количество его ребер. Например буквой e. Давайте, мощность E = e. Ну, конечно, путать с числом e я не предполагаю это дело, ну просто e — это такое обозначение. Это не две целых там семь десятых, примерно. Нет, это просто такое обозначение. Ладно. Вот в нем столько ребер. Утверждается, что в этом графе, и мы сейчас это докажем, разберем в качестве семинарской задачи, утверждается, что в этом графе обязательно найдется двудольный подграф, двудольный подграф, в котором количество ребер не меньше, чем e пополам. То есть сам граф может быть устроен сколь угодно сложно, но в нем обязательно есть двудольный подграф с достаточно большим количеством ребер. Это довольно забавно. В G обязательно есть двудольный подграф, у которого не меньше, чем e пополам ребер. Давайте, прежде чем доказывать этот результат, я все-таки еще раз обозначу его пафос. Вот сам граф может иметь очень большое хроматическое число, может быть его очень трудно покрасить, Тем не менее это обусловлено, ну в каком-то смысле, не только тем, что у графа много ребер. И даже не столько этим. Важно другое. Для того, чтобы граф было трудно покрасить, нужны какие-то иные моменты, связанные с покраской. В любом случае в этом графе есть двудольный, то есть красящийся в два цвета, подграф, который содержит, ну не меньше чем половина от числа ребер исходного графа. По-моему это действительно довольно забавно. Ну давайте доказывать этот результат, и попробуем сообразить, что собственно нужно, для того, чтобы его доказать. Фактически, в чем состоит утверждение. Ну утверждение равносильно тому... утверждение равносильно тому, что можно так разбить множество вершин V нашего графа на две непересекающиеся части, на два непересекающихся подмножества A и B, что между этими множествами A и B проходит не меньше, чем e пополам ребер нашего графа. Вот это, собственно, и утверждается. То есть можно так разбить, что между этими множествами проходит достаточно много ребер. Не меньше, чем e пополам. Ну чудесно! Давайте попробуем решить эту задачу чисто алгоритмически. На самом деле, так, в каком-то смысле забегая вперед, я могу сказать, что очень красивое есть решение у этой задачи, которое использует вероятностный метод, но, поскольку я не предполагаю, что в рамках этого курса слушатели все непременно знают, что такое вероятность и как считать математическое ожидание, то я буду рассказывать чисто алгоритмический подход, и он очень простой на самом деле. Значит, давайте начнем с совершенно произвольного разбиения. Начнем с произвольного разбиения. С произвольного разбиения множества V на какие-то части A и B. Разумеется, никто не гарантирует, никто не утверждает, что начав с такого разбиения, мы сразу получим тот самый граф двудольный, у которого не меньше, чем e пополам ребер. Это было бы нелепо! Хотя, ну мало ли — может повезет! Как раз, случайность-то — она всякая бывает! Некоторая вероятность есть, что мы найдем то, что нужно. Она во всяком случае не нулевая, раз мы верим в существование такого разбиения. Ну хорошо, ладно. Это все словоблудие и болтовня, конечно. Вот начали с такого разбиения. Давайте предположим, предположим, что в одной из частей разбиения, ну например в A — без ограничения общности можно считать, что это происходит в A, ну, может быть и в B — это уж как повезет, ну давайте я просто, для определенности, порешу, что это происходит внутри части A. Так вот, предположим, что в A есть вершина a, из которой строго больше ребер выходит внутрь множества A, нежели количество ребер, которые из нее выходят внутрь множества B. Ну я может быть не очень четко произнес это. Давайте я это сейчас аккуратно напишу. Значит в A есть вершина a такая, что количество ребер, выходящих из этой вершины a, выходящих из a в какие-то вершины A, выходящих в какие-то вершины A, вот это количество строго больше, строго больше, чем количество ребер, количество ребер, выходящих из той же самой вершины a, выходящих из той же самой вершины a, внутрь множества B. Вот предположим, такая вершина есть, и из нее сюда выходит больше ребер, чем сюда. А она сама здесь. Но тогда, если такая вершина есть, давайте переместим ее в часть B. Давайте в этом случае, в этом случае, переместим a в множество B. То есть будем считать, что новое разбиение множества вершин образовано уменьшенным множеством A, из которого выкинули вершинку a, и увеличенным множеством B, в которое, наоборот, эту вершинку добавили. Понятно, что получается такое вот разбиение A', объединенное с B', повторяю, A' — это просто A, к которому... из которого убрали a, а B' — это B, в которое, наоборот, добавили a. Ничего тут особенного не происходит. Так вот получилось такое новое разбиение, и очевидно, что в этом новом разбиении, просто по построению, количество ребер, которые идут между множествами A' и B', ну оно увеличилось как минимум на 1. Количество ребер, которые идут между вот этими дольками, оно увеличилось как минимум на 1 по сравнению с тем количеством ребер, которые шли между исходными, произвольно выбранными дольками A и B. Количество ребер увеличилось. Понятно. Вот. Ну давайте по отношению к этому разбиению A' и B' произведем абсолютно ту же самую процедуру, какую только что произвели по отношению к A и B. То есть если в одной из частей разбиения есть хотя бы одна вершинка, которая обладает вот этим вот свойством, то есть количество ребер, идущих внутрь этой части разбиения для нее строго больше, чем количество ребер, которые выходят в другую часть разбиения, то переместим эту вершинку из своей части в другую, в дополнительную, ну и получится новое разбиение, в котором опять количество ребер между двумя долями вырастет по сравнению с количеством ребер, которое было вот здесь. И будем продолжать эту процедуру до тех пор, пока она не остановится. Понятно, что она остановится. Ну давайте, я все-таки что нибудь напишу. Будем так действовать, будем так делать, покуда это возможно. Покуда это возможно. Ну, друзья, понятно почему в конце концов процесс остановится? Ведь на каждом шаге мы строго увеличиваем количество ребер, которые проходят между частями. Ну понятно, что рано или поздно это количество просто станет, стало бы, если бы это можно было продолжать до бесконечности, это количество просто стало бы строго больше, чем e, раз каждый раз оно увеличивается как минимум на 1. Но в графе-то у нас e ребер, значит этот процесс, конечно, когда нибудь остановится. Ну вот когда он остановится, мы на этом успокоимся. Значит, у нас получится какое-то разбиение V равняется... Не знаю — вот так вот я нарисую A(k), B(k), подразумевая, что k шагов этой процедуры мы проделали, и теперь на выходе у нас получились множества, к которым эту процедуру применить нельзя. Повторяю: рано или поздно она, конечно, останавливается, потому что ребер у нас ограниченное количество. Вот, что значит ее применить нельзя? Что значит получилось такое разбиение, в котором уже дальнейшие действия невозможны при перетаскивании какой-нибудь вершины сюда, или наоборот, какой-то отсюда — туда? Что это значит? А это значит, что, давайте, я напишу «тогда и только тогда», это значит, что какую бы вершину a из A мы ни взяли, какую бы вершину a из A мы ни взяли, но количество ребер из нее в A уже не превосходит, не больше, не больше, чем количество ребер, количество ребер из нее в B. И то же самое верно относительно произвольной вершины из множества B. То есть для любого b из B количество ребер, количество ребер из этой вершины, из нее в B не больше, чем количество ребер из нее, из нее в множество A. Ну то есть, картина такая... Ой, слушайте, я же описался! Как я не заметил! A(k), естественно, вот здесь. Здесь тоже, конечно, A(k). Я забыл, что я ввел такие обозначения. Прошу прощения! Здесь у меня тоже, конечно, будет B(k). Здесь будет B(k), здесь будет B(k), и здесь тоже будет A(k). Конечно мы говорим о тех множествах, которые у нас в итоге получились на выходе. Какую вершину из первого из них ни возьми, ее нельзя добавить к множеству B в рамках той процедуры, которая описана выше. Ну и наоборот, какую вершину из множества B ни возьми, ее тоже нельзя добавить в A с точки зрения вот нашего алгоритма. Количество ребер из нее внутрь этого множества не превосходит количество ребер из нее наружу. Ну и все вроде бы понятно. Картинка такая: у нас есть множество A(k), есть какое-то множество B(k). Никто ни в коем случае не утверждает, что размеры этих долей обязательно одинаковые. Нет, ну у меня просто «сардельки» получились одного размера, но на самом деле они могут быть совершенно разными. Ну вот... Вот есть два таких подмножества, и какую бы вершину из первого множества мы ни взяли, число ребер, которые идут внутри вот этого множества, не превосходит числа ребер, которые выходят из него наружу. И точно так же мы говорим о каждой вершине отсюда. Ну вроде бы совершенно понятно, что таким образом количество ребер, которые идут между разными долями, никак не меньше, чем половина от общего числа ребер. Потому, что и этих меньше, чем сколько идет отсюда сюда, и этих, которые внутри B(k) меньше, чем сколько идет отсюда сюда. Для каждой вершины, значит для всех в совокупности тоже. Ну это и говорит нам о том, что количество ребер, которое я вот здесь нарисовал, которые, так сказать, прошивают вот эти доли между собою, это количество ребер не меньше, чем e пополам. Вот это вот не меньше, чем e пополам, а ровно это нам и требовалось доказать. Все. Вот задача разобрана. По-моему.