06/06/2023 - Weierstrass ha scritto:
Perché non parti dall'algoritmo standard?
Io stavo implementando una versione ricorsiva basata su un'idea di fondo un po' diversa, ma questa versione iterativa la trovo concettualmente più semplice, in pratica si analizzano le celle in ordine di distanza dall'origine finché non viene individuata la destinazione.
Nel far girare il codice per capirne il funzionamento già che c'ero l'ho generalizzato per cella di partenza e arrivo generiche e ho aggiunto una funzione per estrarre il cammino minimo dall'array QUEUE:
#include <stdio.h>
#include <string.h>
#include <windows.h>
#define R 16
#define C 15
typedef struct
{
unsigned int i;
unsigned int j;
unsigned int n;
} nodo;
void estrai_cammino_minimo(nodo v[R * C], int *u[R * C], int m[R][C], unsigned int K)
{
u[0] = &m[v[0].i][v[0].j];
u[v[K].n - 1] = &m[v[K].i][v[K].j];
for(unsigned int k = K; --K;)
{
if(v[K].i == v[k].i ? v[K].j == v[k].j + 1 || v[K].j + 1 == v[k].j : v[K].j == v[k].j && (v[K].i == v[k].i + 1 || v[K].i + 1 == v[k].i))
{
for(u[v[k = K].n - 1] = &m[v[K].i][v[K].j]; v[K].n == v[K - 1].n; --K);
}
}
}
unsigned int cammino_minimo(int *u[R * C], int m[R][C], int *START, int *END)
{
if(!*START && !*END && START != END)
{
int m2[R][C];
memcpy(*m2, *m, R * C * sizeof(**m));
nodo v[R * C];
m2[v[0].i = (START - *m) / C][v[0].j = (START - *m) % C] = v[0].n = 1;
for(unsigned int i_end = (END - *m) / C, j_end = (END - *m) % C, last = 0, curr = 0; curr <= last; ++curr)
{
if(v[curr].i == i_end && v[curr].j == j_end)
{
estrai_cammino_minimo(v, u, m, curr);
return v[curr].n;
}
if(v[curr].j != C - 1 && !m2[v[curr].i][v[curr].j + 1])//RIGHT
{
m2[v[last].i = v[curr].i][v[last].j = v[curr].j + 1] = v[++last].n = v[curr].n + 1;
}
if(v[curr].i != R - 1 && !m2[v[curr].i + 1][v[curr].j])//DOWN
{
m2[v[last].i = v[curr].i + 1][v[last].j = v[curr].j] = v[++last].n = v[curr].n + 1;
}
if(v[curr].j && !m2[v[curr].i][v[curr].j - 1])//LEFT
{
m2[v[last].i = v[curr].i][v[last].j = v[curr].j - 1] = v[++last].n = v[curr].n + 1;
}
if(v[curr].i && !m2[v[curr].i - 1][v[curr].j])//UP
{
m2[v[last].i = v[curr].i - 1][v[last].j = v[curr].j] = v[++last].n = v[curr].n + 1;
}
}
}
return 0;
}
void stampa_cammino_minimo(int *u[R * C], int m[R][C], const unsigned int n)
{
for(unsigned int i = 0; i < R; ++i)
{
printf("\n");
for(unsigned int j = 0; j < C; ++j)
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), m[i][j] ? 12 + 16 * 8 : 7 + 16 * 8);
printf(" %c", 254);
}
}
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 10 + 16 * 8);
for(unsigned int k = 0; k < n; ++k)
{
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), (COORD){(u[k] - *m) % C * 2 + 1, (u[k] - *m) / C + 1});
printf("%c", 254);
}
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), (COORD){0, R});
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
printf("\n\n LUNGHEZZA CAMMINO MINIMO: %u\n", n);
}
int main()
{
int m[R][C] = {{0, 0, 0, 0, 2, 7, 0, 0, 1, 0, 0, 0, 0, 0, 0},
{0, 3, 0, 0, 0, 4, 0, 0, 0, 2, 0, 8, 0, 0, 0},
{0, 0, 8, 0, 0, 0, 6, 0, 0, 0, 5, 0, 5, 0, 0},
{0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 5, 0, 0, 0, 0, 1, 0, 0, 0, 0, 7, 2},
{0, 0, 2, 0, 7, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0},
{5, 0, 0, 0, 0, 5, 0, 0, 9, 0, 0, 0, 0, 4, 0},
{0, 1, 9, 0, 0, 0, 4, 0, 0, 7, 0, 0, 0, 0, 0},
{0, 0, 6, 0, 0, 6, 0, 8, 0, 0, 1, 0, 3, 0, 0},
{0, 0, 0, 0, 3, 0, 1, 0, 0, 0, 0, 8, 0, 0, 0},
{0, 7, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0},
{0, 0, 9, 0, 0, 0, 0, 0, 0, 4, 0, 0, 1, 0, 0},
{0, 1, 0, 4, 0, 0, 9, 0, 2, 0, 0, 9, 5, 8, 0},
{0, 0, 0, 0, 6, 0, 0, 4, 0, 0, 6, 0, 6, 0, 0},
{2, 0, 8, 3, 0, 7, 0, 0, 8, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 9, 0, 0}};
int *u[R * C];
unsigned int n = cammino_minimo(u, m, &m[13][3], &m[1][12]);
stampa_cammino_minimo(u, m, n);
return 0;
}