Для розв'язання задачі необхідно знайти мінімальне остовне дерево. Для цього реалізуємо алгоритм Прима.
Приклад
Побудуємо два графи, наведені у прикладі.
Реалізація алгоритму
Оголосимо глобальні масиви. Координати точок будемо зберігати у масивах та .
#define MAX 1001
#define INF 0x3F3F3F3F
int x[MAX], y[MAX];
int used[MAX], dist[MAX];Функція dist2 обчислює квадрат відстані між точками та .
int dist2(int i, int j)
{
return (x[j] - x[i])*(x[j] - x[i]) + (y[j] - y[i])*(y[j] - y[i]);
}Функція Prim реалізує алгоритм Прима та повертає вагу мінімального остовного дерева.
double Prim(void)
{Ініціалізуємо масиви.
memset(dist, 0x3F, sizeof(dist));
memset(used, 0, sizeof(used));Починаємо побудову мінімального остовного дерева з вершини . Встановлюємо dist[0] = 0 та used[0] = 1. У змінній накопичується значення ваги мінімального остова.
double res = 0;
int i, j, cur = 0;
dist[cur] = 0;
used[cur] = 1;Виконуємо n - 1 ітерацій. На кожній ітерації додаємо до остова одну вершину (таким чином, загалом необхідно додати n - 1 вершин).
for (i = 1; i
Поточна вершина позначається як $cur$. Перебираємо ребра $(cur, j)$ та оновлюємо значення $dist[j]$. У результаті $dist[j]$ зберігає поточну найкоротшу відстань від вершини $j$ до вже побудованої частини мінімального остовного дерева.
\begin{lstlisting}[language=C++]
for (j = 0; j
Шукаємо ребро найменшої довжини, яке буде додано до остова. Для цього знаходимо мінімальне значення $dist[j]$ серед вершин $j$, які ще не належать остову ($used[j] = 0$). Номер вершини з мінімальним значенням $dist[j]$ зберігаємо у змінній $cur$ --- вона стає поточною вершиною.
\begin{lstlisting}[language=C++]
int min = INF;
for (j = 0; j
Вершина $cur$ включається до остова, а ребро довжини $sqrt(dist[cur])$ додається до мінімального остовного дерева.
\begin{lstlisting}[language=C++]
used[cur] = 1;
res += sqrt(dist[cur]);
}
return res;
}Основна частина програми. Послідовно обробляємо тести.
while (scanf("%d",
Читаємо координати точок.
\begin{lstlisting}[language=C++]
for (i = 0; i
Обчислюємо та виводимо вагу мінімального остовного дерева.
\begin{lstlisting}[language=C++]
res = Prim();
printf("%.2lf\n", res);
}Реалізація алгоритму – min_e / end_e
Оголосимо глобальні масиви. Координати точок будемо зберігати у масивах та .
#define MAX 1010
int x[MAX], y[MAX];
int used[MAX], min_e[MAX], end_e[MAX];Функція dist2 обчислює квадрат відстані між точками та .
int dist2(int i, int j)
{
return (x[j] - x[i])*(x[j] - x[i]) + (y[j] - y[i])*(y[j] - y[i]);
}Основна частина програми. Послідовно обробляємо тести.
while (scanf("%d",
Читаємо координати точок.
\begin{lstlisting}[language=C++]
for (i = 0; i
Ініціалізуємо масиви.
\begin{lstlisting}[language=C++]
memset(min_e, 0x3F, sizeof(min_e));
memset(end_e, -1, sizeof(end_e));
memset(used, 0, sizeof(used));Вага мінімального остовного дерева буде накопичуватися у змінній .
dist = min_e[1] = 0;
for (i = 0; i
Шукаємо вершину $v$ з мінімальним значенням $min\_e[v]$ серед вершин, які ще не включені до мінімального остова ($used[v] = 0$).
\begin{lstlisting}[language=C++]
v = -1;
for (j = 0; j
Включаємо вершину $v$ до остова та додаємо до нього ребро $(v, end\_e[v])$.
\begin{lstlisting}[language=C++]
used[v] = 1;
if (end_e[v] != -1) dist += sqrt((double)dist2(v, end_e[v]));Оновлюємо мітки для ребер (v, to), що виходять з вершини . Перебір виконуємо тільки по вершинах , які ще не включені до мінімального остовного дерева (used[to] = 0).
for (to = 0; to
{
int dV_TO = dist2(v, to);
if (!used[to]
{
min_e[to] = dV_TO;
end_e[to] = v;
}
}
}Виводимо вагу мінімального остовного дерева.
printf("%.2lf\n", dist);
}