Per risolvere il problema è necessario trovare l'albero ricoprente minimo. A tal fine implementiamo l'algoritmo di Prim.
Esempio
Costruiamo i due grafi riportati nell'esempio.
Implementazione dell'algoritmo
Dichiariamo gli array globali. Le coordinate dei punti verranno memorizzate negli array e .
#define MAX 1001
#define INF 0x3F3F3F3F
int x[MAX], y[MAX];
int used[MAX], dist[MAX];La funzione dist2 calcola il quadrato della distanza tra i punti e .
int dist2(int i, int j)
{
return (x[j] - x[i])*(x[j] - x[i]) + (y[j] - y[i])*(y[j] - y[i]);
}La funzione Prim implementa l'algoritmo di Prim e restituisce il peso dell'albero ricoprente minimo.
double Prim(void)
{Inizializziamo gli array.
memset(dist, 0x3F, sizeof(dist));
memset(used, 0, sizeof(used));Iniziamo la costruzione dell'albero ricoprente minimo a partire dal vertice . Impostiamo dist[0] = 0 e used[0] = 1. Nella variabile si accumula il valore del peso dell'albero ricoprente minimo.
double res = 0;
int i, j, cur = 0;
dist[cur] = 0;
used[cur] = 1;Eseguiamo n - 1 iterazioni. Ad ogni iterazione aggiungiamo un vertice all'albero ricoprente (in totale è quindi necessario aggiungere n - 1 vertici).
for (i = 1; i < n; i++)
{Il vertice corrente viene indicato come . Scorriamo gli archi (cur, j) e aggiorniamo i valori di dist[j]. Di conseguenza, dist[j] memorizza la distanza minima corrente dal vertice alla parte già costruita dell'albero ricoprente minimo.
for (j = 0; j < n; j++)
if (!used[j] && (dist2(cur, j) < dist[j]))
dist[j] = dist2(cur, j);Cerchiamo l'arco di lunghezza minima che verrà aggiunto all'albero ricoprente. Per farlo, troviamo il valore minimo di dist[j] tra i vertici che non appartengono ancora all'albero ricoprente (used[j] = 0). Il numero del vertice con il valore minimo di dist[j] viene salvato nella variabile — esso diventa il vertice corrente.
int min = INF;
for (j = 0; j < n; j++)
if (!used[j] && (dist[j] < min))
{
min = dist[j];
cur = j;
}Il vertice viene incluso nell'albero ricoprente, e l'arco di lunghezza sqrt(dist[cur]) viene aggiunto all'albero ricoprente minimo.
used[cur] = 1;
res += sqrt(dist[cur]);
}
return res;
}Parte principale del programma. Elaboriamo i test in sequenza.
while (scanf("%d", &n), n)
{Leggiamo le coordinate dei punti.
for (i = 0; i < n; i++)
scanf("%d %d", &x[i], &y[i]);Calcoliamo e stampiamo il peso dell'albero ricoprente minimo.
res = Prim();
printf("%.2lf\n", res);
}Implementazione dell'algoritmo – min_e / end_e
Dichiariamo gli array globali. Le coordinate dei punti verranno memorizzate negli array e .
#define MAX 1010
int x[MAX], y[MAX];
int used[MAX], min_e[MAX], end_e[MAX];La funzione dist2 calcola il quadrato della distanza tra i punti e .
int dist2(int i, int j)
{
return (x[j] - x[i])*(x[j] - x[i]) + (y[j] - y[i])*(y[j] - y[i]);
}Parte principale del programma. Elaboriamo i test in sequenza.
while (scanf("%d", &n), n)
{Leggiamo le coordinate dei punti.
for (i = 0; i < n; i++)
scanf("%d %d", &x[i], &y[i]);Inizializziamo gli array.
memset(min_e, 0x3F, sizeof(min_e));
memset(end_e, -1, sizeof(end_e));
memset(used, 0, sizeof(used));Il peso dell'albero ricoprente minimo verrà accumulato nella variabile .
dist = min_e[1] = 0;
for (i = 0; i < n; i++)
{Cerchiamo il vertice con il valore minimo di tra i vertici non ancora inclusi nell'albero ricoprente minimo (used[v] = 0).
v = -1;
for (j = 0; j < n; j++)
if (!used[j] && (v == -1 || min_e[j] < min_e[v])) v = j;Includiamo il vertice nell'albero ricoprente e aggiungiamo ad esso l'arco (v, end\_e[v]).
used[v] = 1;
if (end_e[v] != -1) dist += sqrt((double)dist2(v, end_e[v]));Aggiorniamo le etichette per gli archi (v, to), uscenti dal vertice . Il ciclo viene eseguito solo sui vertici che non sono ancora stati inclusi nell'albero ricoprente minimo (used[to] = 0).
for (to = 0; to < n; to++)
{
int dV_TO = dist2(v, to);
if (!used[to] && (dV_TO < min_e[to]))
{
min_e[to] = dV_TO;
end_e[to] = v;
}
}
}Stampiamo il peso dell'albero ricoprente minimo.
printf("%.2lf\n", dist);
}