Пара слов о моем алгоритме. Поход примерно как у всех - нагенерировать множество наборов, у которых произведение мало отличается от целевого, а потом из них выбрать

штук так, что у каждой пары наборов ровно одно общее число.
Список оптимизаций такой:
1) Наборы храним в виде битовых полей. Бит с номером

выставлен, если в наборе присуствует простое число с номером

,

. Проверка, что ровно одно общее число у двух наборов, делается за несколько тактов:
bool intersects(uint64_t x, uint64_t y)
{
uint64_t z = x & y;
return z && !(z & (z-1));
}
Для

у нас уже больше 64 простых чисел, и на приходится использовать два 64-битных числа для одного набора, соответственно, чуть усложняется проверка.
Генерировать матрицу смежности было бы невыгодно(хотя я не проверял), потому что она огромная, даже в L3 не влезет, а постоянно тянуть из RAM - накладно.
2) Число два - это самое редко встречающееся в наборах число. Поэтому выгоднее стартовать с набора, содержащего двойку, а потом уже подбирать ему соседей.
3) Начало рекурсивного алгоритма таково: выбираем один набор (назовем его главным), содержащий двойку. Пусть набор состоит из чисел

. Формируем

множеств наборов (из тех, что мы нагенерировали в самом начале) таких, что

-ый набор содержит число

, а больше общих чисел с главным набором нет. Остальная часть алгоритма состоит в том, чтобы выбрать по одному представителю из этих

множеств, чтобы они попарно имели ровно одно общее число.
4) Общая итерация рекурсивного алгоритма такова: пусть на очередном этапе имеется

наборов, один из которых главный, у каждой пары из которых ровно одно общее число. Также у нас имеется

множеств, в которых содержатся кандидаты на оставшиеся

вершин. Мы смотрим, в каком из множеств меньше всего наборов. Если в нем 0 наборов, то возвращаемся на предыдущий уровень рекурсии. Иначе, в цикле перебираем каждого кандидата

из этого множества, вычисляем, какие числа у него общие с имеющимися

наборами - всеми, кроме главного (пусть это числа

), фильтруем оставшиеся

множеств наборов так, чтобы:
а) у каждого набора из множества было ровно одно общее число с

.
б) это общее число не было одним из

.
И переходим на следующий уровень рекурсии.
Дополнительно следим, чтобы сумма

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