Учитывая следующий пример графика:
a d
\ /
b---e
/ \
c f
Не приведет ли "сокращение" края {b, e} к следующему?:
a d
\ /
g
/ \
c f
«Да, это именно так» - амит. Спасибо, я хотел получить правильную спецификацию, прежде чем ответить на Ваш вопрос. Дальнейшие предположения:
- График направлен
- Вершины представлены целыми числами.
- График хранится в двумерном массиве
graph
, graph[x][y]
- вес ребра (x, y); 0 указывает на отсутствие ребра от х до у
Давайте попробуем использовать псевдокод :
void contractEdge(int v1, int v2) {
for (int i = 0; i < n; i++) {
if (graph[v2][i] > 0) {
graph[v1][i] = graph[v1][i] > 0 ? min(graph[v1][i], graph[v2][i]) :
graph[v2][i];
graph[v2][i] = 0;
}
if (graph[i][v2] > 0) {
graph[i][v1] = graph[i][v1] > 0 ? min(graph[i][v1], graph[i][v2]) :
graph[i][v2];
graph[i][v2] = 0;
}
graph[v1][v2] = graph[v2][v1] = 0;
}
}
Код работает так: учитывая ребро {v1, v2}, v1 становится «свернутой» вершиной. Это означает, что вместо вставки новой вершины («g» в моем первом примере) v1 остается в графе, а v2 удаляется из него (при назначении 0 весов на ребрах всем остальным вершинам фактическое количество вершин не изменяется ). Кроме того, все ребра, содержащие v2, сгибаются, чтобы содержать v1.
Теперь этот метод можно вызвать для набора ребер. Время выполнения будет O (n * #edges_to_contract). Я надеюсь, что это поведение, которое вы хотели.
Важно: Если вы используете другое представление для веса ребер, а именно 0 означает ребро с весом 0 и ∞ (бесконечно), указывающее на отсутствие ребра, то ваша проблема становится тривиальной, поскольку все вы должен сделать это:
graph[v1][v2] = graph[v2][v1] = 0
, который эффективно сжимает ребро {v1, v2}, поскольку теперь между v1 и v2 ничего не стоит ехать