Ответ 1
Ваша проблема казалась похожей на взвешенную задачу минимального покрытия вершин (которая является NP-полной). Спасибо @Gareth Rees за пояснения, поясняющие, что я неправильно понимал отношение крышки вершин к набору, который вы ищете. Но вы все еще можете исследовать проблему обложки вершин и литературу, потому что ваша проблема может обсуждаться вместе с ней, поскольку они все еще имеют некоторые функции.
Если вы хотите работать с диаметром вместо взвешенного веса графа, вы можете использовать подход для набора минимального диаметра, который вы связали в своем вопросе. Если ваша текущая дистанционная мера называется d
(той, для которой вы хотите, чтобы точки были наиболее удалены друг от друга), просто определите d' = 1/d
и разрешите задачу минимального расстояния с помощью d'
.
Также может существовать взаимосвязь между каким-либо алгоритмом обработки графа, например normalized cut и подмножество, которое вы ищете. Если ваша дистанционная мера используется в качестве веса графа или сродства между узлами, вы можете изменить существующую функцию резания графика, чтобы она соответствовала вашей целевой функции (поиск группы из k узлов с максимальным суммарным весом).
Это похоже на комбинаторно сложную проблему. Вы можете рассмотреть что-то простое, как симуляционный отжиг. Функция предложения может просто выбрать в точке, которая в настоящее время находится в k
-подмножестве, в случайном порядке и случайно заменить ее точкой, не находящейся в настоящее время в k
-subset.
Вам нужен хороший график охлаждения для температурного режима и, возможно, потребуется использовать повторный нагрев в зависимости от стоимости. Но такого рода это очень просто программировать. Пока n
достаточно мал, вы можете просто случайно выбирать k
-подписки и отжигать в сторону k
-подписки с очень большим полным расстоянием.
Это только приблизит вас, но даже детерминированные методы, вероятно, будут решать это примерно.
Ниже приведен первый взлом в отношении того, что может быть имитированный код отжига. Заметьте, что я не гарантирую этого. Это может быть неэффективное решение, если вычисление расстояния слишком сложно или размер экземпляра проблемы слишком велик. Я использую очень наивное геометрическое охлаждение с фиксированной скоростью охлаждения, и вы также можете захотеть возиться с более привлекательным предложением, чем просто случайным образом обмениваться узлами.
all_nodes = np.asarray(...) # Set of nodes
all_dists = np.asarray(...) # Pairwise distances
N = len(all_nodes)
k = 10 # Or however many you want.
def calculate_distance(node_subset, distances):
# A function you write to determine sum of distances
# among a particular subset of nodes.
# Initial random subset of k elements
shuffle = np.random.shuffle(all_nodes)
current_subset = shuffle[0:k]
current_outsiders = shuffle[k:]
# Simulated annealing parameters.
temp = 100.0
cooling_rate = 0.95
num_iters = 10000
# Simulated annealing loop.
for ii in range(num_iters):
proposed_subset = current_subset.copy()
proposed_outsiders = current_outsiders.copy()
index_to_swap = np.random.randint(k)
outsider_to_swap = np.random.randint(N - k)
tmp = current_subset[index_to_swap]
proposed_subset[index_to_swap] = current_outsiders[outsider_to_swap]
proposed_outsiders[outsider_to_swap] = tmp
potential_change = np.exp((-1.0/temp)*
calculate_distance(proposed_subset,all_dists)/
calculate_distance(current_subset, all_dists))
if potential_change > 1 or potential_change >= np.random.rand():
current_subset = proposed_subset
current_outsiders = proposed_outsiders
temp = cooling_rate * temp