Недавно столкнулся с такой задачей:
Дан неориентированный граф. Нужно разделить его на минимальное количество полных подграфов (и чтобы одна вершина не входила в разные подграфы). Количество вершин <= 100.
Кто-нибудь знает нормальное решение, кроме как писать кучу жадников?
Похоже на эту задачу: http://en.wikipedia.org/wiki/Clique_cover_problem. Если это она — то тут только перебор.
Я пока что даже нормальный перебор не могу придумать, можете подсказать?
Она встретилась на командной олимпиаде, так что странно, если она NP — полная: Задача I
1) Построим граф, в котором между вершинами существует ребро, если в соответствующем поле таблицы стоит единица, т.е. если i и j животных нельзя посадить в одну клетку.
2) Разобьем граф на компоненты связанности. Ответом на задачу будет максимальный ответ из всех ответов для каждой компоненты.
3) Рассмотрим ответ для компоненты: Выберем вершину и запустим из нее бфс. Будем помечать вершины цветами 1 и 2, если мы "берем" вершину или "не берем", соответственно. Если мы находимся в вершине с цветом 1, то все смежные с ней вершины будут иметь цвет 2. Наоборот если мы сейчас находимся в вершине с цветом 2. Теперь скажем, что вершины с цветом 1 составляют группу(Понятно что между этими вершинами не будет ребер). Удалим эти вершины. Дальше решим задачу для новых образовавшихся компонент.
Ну про 1 и 2 пункт я догадался, а с 3 вообще не понятно: мы выходим только в случае, если текущий граф полный? тогда почему это должно работать?
Нам выгодно брать как можно больше вершин в группу. Т.к. если мы не возьмем ее сейчас, нам придется взять ее потом, и ответ всяко не улучшится. Ну по сути это жадный алгоритм. Про полный граф я нигде не упоминал.
Все ясно, не так прочитал первый пункт, извиняюсь. Выглядит правдоподобно. Но меня смущает тот факт, что вроде этот бфс работает за O(N+M)(может еще какая-то константа). Может я не правильно оцениваю сложность этого алгоритма?
И еще, если ставить ребра при 0 в матрице, то нужно находить минимальное кол-во полных подграфов, которая описана как NP-полная, которую никто за линию не решил.
Нет, неправильно. За O(n + m) будет работать 1 бфс. Тут их может получиться больше. Т.е. после того как мы удалили группу вершин, на оставшихся нам снова надо запустить бфс.
Непонятно, а что мешает двум вершинам цвета 1 оказаться связанными ребром?
Как я понял, тут надо использовать перекраску в нескольких случаях: если мы не посещали вершину, и если у текущей вершины цвет 1 и есть ребро в вершину цвета 1, то перекрасить другую вершину. Из-за этого я не могу нормально определить асимптотику и вообще не будет ли зацикливания.
Ну если граф не двудольный, то в любом случае у нас не выйдет его покрасить в 2 цвета.
После удаления вершин мы начинаем разбивать оставшиеся компоненты. О двудольности речи нигде не шло.
Так чтобы что-то удалить, нам нужно граф раскрасить, разве не это написано в описании алгоритма? Так вот, раскрасить мы его не сможем, если он не двудольный.
На всего лишь нужно найти группу вершин, в которую обязательно входит та вершина из которой мы запустили бфс и она имеет максимальный размер. Я предложил способ выделения такого множества. Наверно, стоило оговорить что если две вершины принадлежат множеству 1 и соединены ребром, то одну из них стоит удалить. Я посчитал что это уже к тонкостям реализации относится.
Максимальный по включению или количеству вершин? Если второе, то это NP-полная задача. Если первое, то это, очевидно, неправильно.
Что неправильно, мне не очевидно. Условие, гласящее о том, что любые 2 вершины содержащиеся в первом множестве не должны иметь ребра не обязано выполняться для второго множества. Второе множество будет обработано в дальнейшем.
Ну рассмотрим граф со следующими ребрами: 1-2, 2-3, 3-4, 4-5, 5-2. В начале удалим вершины 1 и 4, поскольку они образуют максимальное по включению независимое множество. После этого останется цепочка из 3 вершин, которую можно покрыть двумя множествами. Итого, получили ответ 3. Но ведь граф можно покрыть и двумя множествами: {1, 3, 5} и {2, 4}.
1) В данном случае алгоритм найдет 2 множества. {1, 3, 5} и {2, 4}. Это не трудно увидеть, если нарисовать граф. Возможно, увидев код, Вы лучше поймете идею моего решения.
http://pastebin.com/dpNXHiuP
2) Меня действительно напрягает то, что решенная мною задача по сути является эквивалентной NP-полной, описанной выше, но работает за полиномиальное время.
Я прекрасно понимаю, какие вершины найдет алгоритм. Но он — не более, чем шаманство для поиска максимального по включению независимого множества. Просто не хотелось придумывать какой-то сложный граф, чтобы завалить именно такой способ выбора.
Еще с самого начала было ясно, что задача NP-полная и описанный алгоритм — попытка жадно найти приближенное решение. Я просто попытался указать на ошибку, но вижу что спорить бесполезно.
Наверное, все — таки Вы правы. Что то я очень сильно сомневаюсь в своих способностях придумать полиномиальное решение для NP — полной задачи.
Это уже к реализации относится.