Introducere în problema labirintului aici.
Enunț
c) Modificați funcția de afișare a drumului astfel încât să afișeze toate drumurile minime existente.Explicație
Cum se cere modificarea funcției existente, nu crearea unei noi funcții, există opțiunea de a transforma funcția din recursivă în nerecursivă și de a folosi un arbore (fiecare nod al arborelui are cel mult 4 descendenți direcți, în structura de nod a arborelui se rețin coordonatele x - implicit -1, y - implicit -1 și părintele - implicit NULL).Funcția recursivă de aflare a unui singur drum optim este următoarea:
void drum_unic(int D[maxn][maxn], int N, int x, int y,
ofstream &out)
{
if (D[x][y] == 0)
{
out << "2 5\n"; // aici se înlocuiește "2 5" cu poziția de pornire
return;
}
for (int i = 0; i < 4; ++i)
{
int newx = x + dx[i];
int newy = y + dy[i];
if (valid(N, newx, newy))
if (D[newx][newy] == D[x][y] - 1)
{ drum_unic(D, N, newx, newy, out);
break;
}
}
out << x << ' ' << y << "\n";
}
Funcția nerecursivă de aflare a unui singur drum optim este următoarea:
void drum_unic_nerec(int D[maxn][maxn],
int N, ofstream &out)
{
queue<pair<int, int>> Q;
Q.push(make_pair(2, 5)); // aici se înlocuiește (2, 5) cu poziția de pornire
while (!Q.empty())
{
pair<int, int> p = Q.front();
Q.pop();
out << p.first << ' ' << p.second << endl;
for (int i = 0; i < 4; ++i)
{
int newx = p.first + dx[i];
int newy = p.second + dy[i];
if (valid(N, newx, newy))
if (D[newx][newy] == D[p.first][p.second] + 1)
{
Q.push(make_pair(newx, newy));
break;
}
}
}
}
Funcția nerecursivă de afișare a tuturor drumurilor optime este următoarea:
void toate_drumurile_nerec(int D[maxn][maxn], int N, ofstream &out) { Nod *nod = new Nod; nod->x = 2; // aici se înlocuiește (2, 5) cu poziția de pornire nod->y = 5; queue<Nod *> Q; Q.push(nod); while (!Q.empty()) { Nod *p = Q.front(); Q.pop(); for (int i = 0; i < 4; ++i) { int newx = p->x + dx[i]; int newy = p->y + dy[i]; if (valid(N, newx, newy)) if (D[newx][newy] == D[p->x][p->y] + 1) { Nod *v = new Nod; v->x = newx; v->y = newy; v->parinte = p; if (p->copil1 == NULL) { p->copil1 = v; } else if (p->copil2 == NULL) { p->copil2 = v; } else if (p->copil3 == NULL) { p->copil3 = v; } else if (p->copil4 == NULL) { p->copil4 = v; } else { // eroare } Q.push(v); } } } // afisare: stack<Nod *> s; s.push(nod); // parcurgere in adancime pentru gasirea tuturor frunzelor while (!s.empty()) { Nod *n = s.top(); s.pop(); bool are_descendenti_directi = false; if (n->copil1 != NULL) { s.push(n->copil1); are_descendenti_directi = true; } if (n->copil2 != NULL) { s.push(n->copil2); are_descendenti_directi = true; } if (n->copil3 != NULL) { s.push(n->copil3); are_descendenti_directi = true; } if (n->copil4 != NULL) { s.push(n->copil4); are_descendenti_directi = true; } // daca este frunza (nu are descendenti directi) if (!are_descendenti_directi) { afiseaza_drum_radacina_frunza(n, out); // sau: afiseaza_drum_frunza_radacina(n); } } }
Această funcție folosește următoarea structură:
struct Nod { Nod *parinte = NULL; Nod *copil1 = NULL; Nod *copil2 = NULL; Nod *copil3 = NULL; Nod *copil4 = NULL; int x = -1, y = -1; };
și în plus, următoarele două funcții de afișare:
// afiseaza drumul de la o frunza la radacina void afiseaza_drum_frunza_radacina(Nod *f, ofstream &out) { while (f != NULL) { out << f->x << " " << f->y << endl; f = f->parinte; } out << endl; } // afiseaza drumul de la radacina la o frunza void afiseaza_drum_radacina_frunza(Nod *f, ofstream &out) { stack<Nod *> s; while (f != NULL) { s.push(f); f = f->parinte; } while (!s.empty()) { f = s.top(); s.pop(); out << f->x << " " << f->y << endl; } out << endl; }
In rest codul este la fel ca in articolul de la link-ul de la începutul acestui articol. In funcția main se face apelul:
toate_drumurile_nerec(D, N, out);
după deschiderea fișierului lee.out care se face după apelul la funcția Lee.
Exemplu
Pentru datele de intrare:5
1 1 1 1 1
1 0 0 0 0
1 0 0 1 1
1 0 0 1 1
1 0 1 1 1
datele de ieșire sunt:
6
2 5
2 4
2 3
2 2
3 2
4 2
5 2
2 5
2 4
2 3
3 3
3 2
4 2
5 2
2 5
2 4
2 3
3 3
4 3
4 2
5 2
Niciun comentariu:
Trimiteți un comentariu