// https://www.geeksforgeeks.org/shortest-path-in-a-binary-maze/ // https://www.techiedelight.com/find-shortest-path-source-destination-matrix-satisfies-given-constraints/ // Plus court chemin entre deux cellules. // Version "BFS" - parcours en largeur #include #include #include using namespace std; int m = 0, n = 0; // Lignes, colonnes // Coordonnées dans la matrice struct point_t { int x, y; point_t() : x(0), y(0) { } point_t(int _x, int _y) : x(_x), y(_y) { } }; // Structure de noeud pour la file d'attente utilisée dans le parcours BFS struct node_t { point_t pt; // Coordonnées d'une cellule node_t *parent; // Pointeur vers le noeud parent du noeud courant int dist; // Distance de la cellule à l'origine (0, 0) }; // Vérification si (i, j) est une cellule valide ou non bool isValid(const int i, const int j) { return i >= 0 && i < m && j >= 0 && j < n; } // isValid() // Fonction récursive pour reconstruire le chemin void buildPath(const node_t *node, vector> &path) { if(node != nullptr) { buildPath(node->parent, path); path.push_back(make_pair(node->pt.x, node->pt.y)); } } // buildPath() void printPath(const vector> &path) { for(int i = 0; i < m; i++, cout << '\n') { for(int j = 0; j < n; j++) { // est-ce que {i, j} est dans le path? auto p = make_pair(i, j); if(find(path.begin(), path.end(), p) != path.end()) fmt::print(fg(fmt::color::light_pink), "{:2} ", '*'); else fmt::print(fg(fmt::color::light_green), "{:2} ", '.'); } } } // printPath() // Directions d'un "4-voisinage" vector rowNum = {-1, 0, 0, 1}; vector colNum = { 0, -1, 1, 0}; // Distance la plus courte entre une cellule 'src' et une cellule 'dst'. // Parcours en largeur int BFS(const vector> &mat, const point_t src, const point_t dst) { // Est-ce que les deux cellules contiennent un '1' ? if(mat[src.x][src.y] == 0 || mat[dst.x][dst.y] == 0) return -1; auto visited = vector>(m, vector(n, false)); // Marque la cellule source comme visitée visited[src.x][src.y] = true; // File d'attente de pointeurs de noeuds pour le parcours en largeur queue q; // La cellule source n'a pas de parent et a une distance nulle : node_t *s = new node_t{src, nullptr, 0}; q.push(s); // On enfile la cellule source // Parcours en largeur à partir de la cellule source while(!q.empty()) { node_t *curr = q.front(); point_t pt = curr->pt; // Destination atteinte, on a fini if(pt.x == dst.x && pt.y == dst.y) { vector> path; int distMin = curr->dist; buildPath(curr, path); printPath(path); return distMin; } // Sinon on défile la cellule en tête de file et on enfile ses cellules adjacentes q.pop(); for(size_t i = 0; i < rowNum.size(); i++) { int row = pt.x + rowNum[i]; int col = pt.y + colNum[i]; // Si la cellule adjacente est valide et non visitée, on l'enfile if(isValid(row, col) && mat[row][col] && !visited[row][col]) { visited[row][col] = true; // La case {row, col} est valide et non visitée // et elle a pour noeud parent 'curr'. node_t *Adjcell = new node_t{{row, col}, curr, curr->dist + 1}; q.push(Adjcell); } } } // -1 si la destination ne peut pas être atteinte return -1; } // BFS() int main() { // Lecture des données cin >> m >> n; // lignes, colonnes // Matrice d'adjacences auto mat = vector>(m, vector(n, 0)); for(int i = 0; i < m * n; i++) cin >> mat[i / n][i % n]; // Résolution point_t src = {0, 0}; point_t dst = {m - 1, n - 1}; int dist = BFS(mat, src, dst); // Parcours en largeur if(dist != -1) cout << dist << '\n'; else cout << "No solution.\n"; return 0; } // main()