2501_92411430 2025-06-11 08:38 采纳率: 0%
浏览 14

“如何输出迷宫问题中所有到达终点的可行路径?”


#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <time.h>
#include <string.h>
#include <conio.h>

#define ROW 10
#define COL 10

// 控制台颜色定义
#define RED 12
#define GREEN 10
#define BLUE 9
#define WHITE 15
#define YELLOW 14

// 迷宫地图
char maze[ROW][COL];

// 记录访问状态
int visited[ROW][COL];

// 坐标结构体
typedef struct {
    int x, y;
} Node;

// 路径结构体
typedef struct {
    Node* nodes;
    int size;
    int capacity;
} Path;

// 全局变量存储所有路径
Path allPaths[1000];
int pathCount = 0;


// 设置控制台颜色
void setColor(int color) {
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), color);
}

// 清屏 - 改为只移动光标而不清屏
void clearScreen() {
    //清屏
    system("cls");    
    // 将光标移动到左上角
//    COORD coord = {0, 0};
//    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
}

// 等待指定毫秒
void wait(int ms) {
    Sleep(ms);
}

// 初始化路径
void initPath(Path* path) {
    path->nodes = NULL;
    path->size = 0;
    path->capacity = 0;
}

// 添加节点到路径
void addToPath(Path* path, Node node) {
    if (path->size >= path->capacity) {
        path->capacity = path->capacity == 0 ? 1 : path->capacity * 2;
        path->nodes = (Node*)realloc(path->nodes, path->capacity * sizeof(Node));
    }
    path->nodes[path->size++] = node;
}

// 释放路径内存
void freePath(Path* path) {
    if (path->nodes != NULL) {
        free(path->nodes);
        path->nodes = NULL;
    }
    path->size = 0;
    path->capacity = 0;
}

// 复制路径
void copyPath(Path* dest, Path* src) {
    dest->size = src->size;
    dest->capacity = src->capacity;
    dest->nodes = (Node*)malloc(dest->capacity * sizeof(Node));
    memcpy(dest->nodes, src->nodes, src->size * sizeof(Node));
}

// 初始化迷宫
void initMaze() {
    // 初始化为全墙
    for (int i = 0; i < ROW; i++) {
        for (int j = 0; j < COL; j++) {
            maze[i][j] = '1';
        }
    }
}

// 判断是否可以走
int isValid(int x, int y) {
    return x >= 0 && x < ROW && y >= 0 && y < COL &&
    (maze[x][y] == '0' || maze[x][y] == 'E') && !visited[x][y];
}

// 重置访问状态
void resetVisited() {
    for (int i = 0; i < ROW; i++) {
        for (int j = 0; j < COL; j++) {
            visited[i][j] = 0;
        }
    }
}

// 检查迷宫是否可解(BFS算法)
int isMazeSolvable() {
    resetVisited();
    // 使用数组模拟队列
    Node queue[ROW * COL];
    int front = 0, rear = 0;
    int dir[4][2] = {{0,1}, {1,0}, {0,-1}, {-1,0}}; // 右、下、左、上
    Node start = {1, 0}; // S 的位置
    queue[rear++] = start;
    visited[start.x][start.y] = 1;
    while (front < rear) {
        Node cur = queue[front++];
        if (maze[cur.x][cur.y] == 'E') {
            return 1; // 找到终点,迷宫可解
        }
        for (int i = 0; i < 4; i++) {
            int nx = cur.x + dir[i][0];
            int ny = cur.y + dir[i][1];
            
            if (isValid(nx, ny)) {
                visited[nx][ny] = 1;
                Node next = {nx, ny};
                queue[rear++] = next;
            }
        }
    }
    return 0; // 未找到路径,迷宫不可解
}

// 随机生成迷宫并确保可解
void generateValidMaze() {
    int attempts = 0;
    const int max_attempts = 100; // 最大尝试次数
    do {
        attempts++;
        if (attempts > max_attempts) {
            printf("无法生成可解迷宫,请调整参数后重试!\n");
            exit(1);
        }
        srand((unsigned int)time(NULL) + attempts);
        initMaze();
        // 设置起点和终点
        maze[1][0] = 'S'; // 起点
        maze[ROW-2][COL-1] = 'E'; // 终点
        // 随机生成通路
        for (int i = 1; i < ROW-1; i++) {
            for (int j = 1; j < COL-1; j++) {
                if (rand() % 100 < 70) { // 70%概率是通路
                    maze[i][j] = '0';
                }
            }
        }
        // 确保起点和终点附近有通路
        maze[1][1] = '0';
        maze[ROW-2][COL-2] = '0';
    } while (!isMazeSolvable());
    printf("生成有效迷宫,尝试次数: %d\n", attempts);
}

// 打印当前迷宫状态
void printMaze(int fullRedraw) {
    static char lastMaze[ROW][COL] = {0};
    for (int i = 0; i < ROW; i++) {
        for (int j = 0; j < COL; j++) {
            // 只重绘发生变化的部分
            if (fullRedraw || maze[i][j] != lastMaze[i][j]) {
                // 移动光标到指定位置
                COORD coord = {(SHORT)(j*2), (SHORT)i};
                SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
                char ch = maze[i][j];
                if (ch == 'X') setColor(RED);
                else if (ch == 'B') setColor(BLUE);
                else if (ch == 'E') setColor(GREEN);
                else if (ch == 'S') setColor(YELLOW);
                else if (ch == 'P') setColor(GREEN); // 最终路径
                else setColor(WHITE);
                printf("%c ", ch);
                lastMaze[i][j] = maze[i][j];
            }
        }
    }
    setColor(WHITE);
}

// 迷宫路径搜索(使用栈实现深度优先)
void solveMazeDFS_Stack() {
    resetVisited();
    // 使用数组模拟栈
    Node stack[ROW * COL];
    Path paths[ROW * COL];
    int top = -1;
    int dir[4][2] = {{0,1}, {1,0}, {0,-1}, {-1,0}}; // 右、下、左、上
    Node start = {1, 0}; // S 的位置
    Path startPath;
    initPath(&startPath);
    addToPath(&startPath, start);
    stack[++top] = start;
    paths[top] = startPath;
    visited[start.x][start.y] = 1;
    // 初始全绘制
    printMaze(1);
    wait(100);
    while (top >= 0) {
        Node cur = stack[top];
        Path curPath = paths[top];
        top--;
        if (maze[cur.x][cur.y] != 'S' && maze[cur.x][cur.y] != 'E') {
            maze[cur.x][cur.y] = 'X'; // 红色路径
        }
        // 动态显示 - 减少刷新频率
        static int counter = 0;
        if (++counter % 5 == 0) { // 每5步刷新一次
            printMaze(0);
            wait(50); // 减少等待时间
        }
        if (maze[cur.x][cur.y] == 'E') {
            // 找到终点,标记路径
            for (int i = 0; i < curPath.size; i++) {
                Node node = curPath.nodes[i];
                if (maze[node.x][node.y] != 'S' && maze[node.x][node.y] != 'E') {
                    maze[node.x][node.y] = 'P';
                }
            }
            freePath(&curPath);
            break;
        }
        for (int i = 0; i < 4; i++) {
            int nx = cur.x + dir[i][0];
            int ny = cur.y + dir[i][1];
            if (isValid(nx, ny)) {
                visited[nx][ny] = 1;
                Node next = {nx, ny};
                Path newPath;
                initPath(&newPath);
                copyPath(&newPath, &curPath);
                addToPath(&newPath, next);
                stack[++top] = next;
                paths[top] = newPath;
            }
        }
        freePath(&curPath);
        // 回退路径标记为蓝色
        if (maze[cur.x][cur.y] == 'X') {
            maze[cur.x][cur.y] = 'B';
        }
    }
    // 最终展示结果
    printMaze(1);
}

// 队列实现的广度优先搜索(BFS)
void solveMazeBFS_Queue() {
    resetVisited();
    // 使用数组模拟队列
    Node queue[ROW * COL];
    Path paths[ROW * COL];
    int front = 0, rear = 0;
    int dir[4][2] = {{0,1}, {1,0}, {0,-1}, {-1,0}}; // 右、下、左、上
    Node start = {1, 0}; // S 的位置
    Path startPath;
    initPath(&startPath);
    addToPath(&startPath, start);
    queue[rear] = start;
    paths[rear] = startPath;
    rear++;
    visited[start.x][start.y] = 1;
    // 初始全绘制
    printMaze(1);
    wait(100);
    while (front < rear) {
        Node cur = queue[front];
        Path curPath = paths[front];
        front++;
        if (maze[cur.x][cur.y] != 'S' && maze[cur.x][cur.y] != 'E') {
            maze[cur.x][cur.y] = 'X'; // 红色路径
        }
        // 动态显示 - 减少刷新频率
        static int counter = 0;
        if (++counter % 5 == 0) { // 每5步刷新一次
            printMaze(0);
            wait(50); // 减少等待时间
        }
        if (maze[cur.x][cur.y] == 'E') {
            // 找到终点,标记路径
            for (int i = 0; i < curPath.size; i++) {
                Node node = curPath.nodes[i];
                if (maze[node.x][node.y] != 'S' && maze[node.x][node.y] != 'E') {
                    maze[node.x][node.y] = 'P';
                }
            }
            freePath(&curPath);
            break;
        }
        for (int i = 0; i < 4; i++) {
            int nx = cur.x + dir[i][0];
            int ny = cur.y + dir[i][1];
            if (isValid(nx, ny)) {
                visited[nx][ny] = 1;
                Node next = {nx, ny};
                Path newPath;
                initPath(&newPath);
                copyPath(&newPath, &curPath);
                addToPath(&newPath, next);
                queue[rear] = next;
                paths[rear] = newPath;
                rear++;
            }
        }
        freePath(&curPath);
    }
    // 最终展示结果
    printMaze(1);
}

// 递归实现深度优先搜索的辅助函数
void dfsHelper(int x, int y, Path* path, int* found) {
    if (*found) return;
    if (maze[x][y] == 'E') {
        *found = 1;
        for (int i = 0; i < path->size; i++) {
            Node node = path->nodes[i];
            if (maze[node.x][node.y] != 'S' && maze[node.x][node.y] != 'E') {
                maze[node.x][node.y] = 'P';
            }
        }
        return;
    }
    int dir[4][2] = {{0,1}, {1,0}, {0,-1}, {-1,0}};
    for (int i = 0; i < 4; i++) {
        int nx = x + dir[i][0];
        int ny = y + dir[i][1];
        if (isValid(nx, ny)) {
            visited[nx][ny] = 1;
            if (maze[nx][ny] != 'E') maze[nx][ny] = 'X';
            static int counter = 0;
            if (++counter % 5 == 0) {
                printMaze(0);
                wait(200);
            }
            Node next = {nx, ny};
            addToPath(path, next);
            dfsHelper(nx, ny, path, found);
            if (path->size > 0) {
                path->size--;
            }
            if (!(*found) && maze[nx][ny] == 'X') {
                maze[nx][ny] = 'B';    
                if (counter % 5 == 0) {
                    printMaze(0);
                    wait(200);
                }
            }
        }
    }
}

// 递归实现深度优先搜索
void solveMazeDFS_Recursive() {
    resetVisited();
    Path path;
    initPath(&path);
    Node start = {1, 0};
    addToPath(&path, start);
    visited[start.x][start.y] = 1;
    printMaze(1);
    wait(100);
    int found = 0;
    dfsHelper(start.x, start.y, &path, &found);
    freePath(&path);
    printMaze(1);
}

// 清除路径标记
void clearPath() {
    for (int i = 0; i < ROW; i++) {
        for (int j = 0; j < COL; j++) {
            // 只清除路径标记,保留迷宫结构和起点终点
            if (maze[i][j] == 'X' || maze[i][j] == 'B' || maze[i][j] == 'P') {
                maze[i][j] = '0';
            }
        }
    }
    resetVisited();  // 同时重置访问状态
}

// 递归实现深度优先搜索的辅助函数(用于查找所有路径)
void dfsAllPathsHelper(int x, int y, Path* path) {
    if (maze[x][y] == 'E') {
        // 路径数超限则不再保存,避免内存溢出
        if (pathCount < 1000) {
            initPath(&allPaths[pathCount]);
            copyPath(&allPaths[pathCount], path);
            pathCount++;
        }
        return;
    }
    int dir[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
    for (int i = 0; i < 4; i++) {
        int nx = x + dir[i][0];
        int ny = y + dir[i][1];
        if (isValid(nx, ny)) {
            visited[nx][ny] = 1;
            Node next = {nx, ny};
            addToPath(path, next);
            dfsAllPathsHelper(nx, ny, path);
            // 严格回溯,确保 visited 状态正确
            if (path->size > 0) {
                path->size--;
            }
            visited[nx][ny] = 0;
        }
    }
}

// 查找所有路径
void findAllPaths() {
    resetVisited();
    pathCount = 0;
    // 防止多次调用未初始化,先清空 allPaths 残留
    for (int i = 0; i < pathCount; i++) {
        freePath(&allPaths[i]);
    }
    Path path;
    initPath(&path);
    Node start = {1, 0};
    addToPath(&path, start);
    visited[start.x][start.y] = 1;
    dfsAllPathsHelper(start.x, start.y, &path);
    freePath(&path);
    // 打印路径(独立清屏)
    clearScreen();
    printf("找到 %d 条路径:\n", pathCount);
    for (int i = 0; i < pathCount; i++) {
        printf("路径 %d: ", i + 1);
        for (int j = 0; j < allPaths[i].size; j++) {
            printf("(%d,%d)", allPaths[i].nodes[j].x, allPaths[i].nodes[j].y);
            if (j < allPaths[i].size - 1) {
                printf(" -> ");
            }
        }
        printf("\n");
        // 及时释放路径内存,避免堆积
        freePath(&allPaths[i]);
    }
    printf("\n按任意键返回主菜单...");
    getch();
    // 彻底清屏并重置绘制状态,确保后续功能正常
    clearScreen();
    // 重新全量绘制迷宫,恢复可视化环境
    printMaze(1); 
}

// 判断是否重新生成迷宫
void re_generate() {
    clearScreen();
    char flag;
    printf("\n是否需要重新生成迷宫(Y/N):");
    flag = getchar();
    // 清除输入缓冲区
    while (getchar() != '\n');
    
    // 验证输入
    while (flag != 'y' && flag != 'Y' && flag != 'n' && flag != 'N') {
        printf("输入错误,请重新输入(Y/N):");
        flag = getchar();
        while (getchar() != '\n');
    }
    
    // 重新生成迷宫或清除路径
    if (flag == 'Y' || flag == 'y') {
        generateValidMaze();
    } else {                        
        clearPath();
        printf("路径已清除,可以尝试其他算法!\n");
        wait(1000);
    }
}

// 显示菜单
void showMenu() {
    printf("\n=== 迷宫求解算法 ===\n");
    printf("1. 使用栈实现深度优先搜索(DFS)\n");
    printf("2. 使用队列实现广度优先搜索(BFS)\n");    
    printf("3. 使用递归实现深度优先搜索(DFS)\n");
    printf("4. 查找所有路径\n");
    printf("5. 退出\n");
    printf("请选择(1-5): ");
}

// 更新主函数
int main() {
    // 设置控制台缓冲区大小,防止滚动
    system("mode con cols=25 lines=30");
    int choice;
    // 初始迷宫
    generateValidMaze();
    
    do {
        clearScreen();
        printMaze(1);
        showMenu();
        
        // 输入验证
        while (scanf("%d", &choice) != 1 || choice < 1 || choice > 5) {
            printf("无效选择,请输入1-5的数字:");
            while (getchar() != '\n'); // 清除错误输入
        }
        while (getchar() != '\n'); // 清除输入缓冲区
        
        switch (choice) {
            case 1:
                solveMazeDFS_Stack();
                printf("\n\n\n\n\n\n\n\n\nDFS(栈) 执行完毕,按任意键返回菜单...");
                getch();
                break;
            case 2:
                solveMazeBFS_Queue();
                printf("\n\n\n\n\n\n\n\n\nBFS(队列) 执行完毕,按任意键返回菜单...");
                getch();
                break;
            case 3:
                solveMazeDFS_Recursive();
                printf("\n\n\n\n\n\n\n\n\nDFS(递归) 执行完毕,按任意键返回菜单...");
                getch();
                break;
            case 4:
                findAllPaths();
                break;
            case 5:
                printf("程序结束\n");
                return 0;
        }
        re_generate();
    } while (choice != 5);
}

现在要查找所有路径更新下,使得输出可到达终点的路径,希望在我的代码的基础上,进行更新

  • 写回答

7条回答 默认 最新

  • 檀越@新空间 2025-06-11 08:39
    关注

    上午好☀️☀️☀️️
    本答案参考通义千问

    要解决的问题是如何输出迷宫问题中所有到达终点的可行路径,我们需要对现有的代码进行一些修改和补充。以下是详细的解决方案:


    解决方案

    1. 使用深度优先搜索(DFS)遍历迷宫

      • DFS 是一种递归算法,非常适合用于寻找所有可能的路径。
      • 在递归过程中,记录当前路径,并在到达终点时将路径保存到 allPaths 中。
    2. 优化路径存储

      • 使用动态数组存储路径,避免固定大小的限制。
      • 在递归结束时,复制当前路径到全局路径数组 allPaths
    3. 实现路径打印功能

      • 提供一个函数,用于格式化输出所有找到的路径。

    修改后的代码

    以下是完整的代码实现:

    #include <stdio.h>
    #include <stdlib.h>
    #include <windows.h>
    #include <time.h>
    #include <string.h>
    #include <conio.h>
    
    #define ROW 10
    #define COL 10
    
    // 控制台颜色定义
    #define RED 12
    #define GREEN 10
    #define BLUE 9
    #define WHITE 15
    #define YELLOW 14
    
    // 迷宫地图
    char maze[ROW][COL];
    
    // 记录访问状态
    int visited[ROW][COL];
    
    // 坐标结构体
    typedef struct {
        int x, y;
    } Node;
    
    // 路径结构体
    typedef struct {
        Node* nodes;
        int size;
    } Path;
    
    // 全局变量存储所有路径
    Path allPaths[1000];
    int pathCount = 0;
    
    // 设置控制台颜色
    void setColor(int color) {
        SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), color);
    }
    
    // 初始化路径
    void initPath(Path* path) {
        path->nodes = NULL;
        path->size = 0;
    }
    
    // 添加节点到路径
    void addToPath(Path* path, Node node) {
        path->nodes = (Node*)realloc(path->nodes, (path->size + 1) * sizeof(Node));
        path->nodes[path->size++] = node;
    }
    
    // 释放路径内存
    void freePath(Path* path) {
        if (path->nodes != NULL) {
            free(path->nodes);
            path->nodes = NULL;
        }
        path->size = 0;
    }
    
    // 初始化迷宫
    void initMaze() {
        // 初始化为全墙
        for (int i = 0; i < ROW; i++) {
            for (int j = 0; j < COL; j++) {
                maze[i][j] = '1';
            }
        }
    }
    
    // 判断是否可以走
    int isValid(int x, int y) {
        return x >= 0 && x < ROW && y >= 0 && y < COL &&
               (maze[x][y] == '0' || maze[x][y] == 'E') && !visited[x][y];
    }
    
    // 重置访问状态
    void resetVisited() {
        for (int i = 0; i < ROW; i++) {
            for (int j = 0; j < COL; j++) {
                visited[i][j] = 0;
            }
        }
    }
    
    // 深度优先搜索:寻找所有路径
    void dfs(int x, int y, Path currentPath) {
        // 标记当前节点为已访问
        visited[x][y] = 1;
    
        // 将当前节点加入路径
        addToPath(&currentPath, (Node){x, y});
    
        // 如果到达终点,保存路径
        if (maze[x][y] == 'E') {
            copyPath(&allPaths[pathCount++], &currentPath);
        }
    
        // 定义四个方向:右、下、左、上
        int dir[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
    
        // 遍历四个方向
        for (int i = 0; i < 4; i++) {
            int nx = x + dir[i][0];
            int ny = y + dir[i][1];
    
            if (isValid(nx, ny)) {
                dfs(nx, ny, currentPath);
            }
        }
    
        // 回溯:撤销访问标记
        visited[x][y] = 0;
    
        // 移除最后一个节点,回溯到上一层
        currentPath.size--;
    }
    
    // 打印所有路径
    void printAllPaths() {
        printf("\n找到以下所有路径:\n");
        for (int i = 0; i < pathCount; i++) {
            printf("路径 %d:\n", i + 1);
            for (int j = 0; j < allPaths[i].size; j++) {
                printf("(%d, %d) ", allPaths[i].nodes[j].x, allPaths[i].nodes[j].y);
            }
            printf("\n");
        }
    }
    
    // 主函数
    int main() {
        // 生成迷宫
        generateValidMaze();
    
        // 初始化路径
        Path currentPath;
        initPath(&currentPath);
    
        // 从起点开始搜索
        dfs(1, 0, currentPath);
    
        // 输出所有路径
        printAllPaths();
    
        return 0;
    }
    

    代码说明

    1. dfs 函数

      • 使用递归实现深度优先搜索。
      • 在每次递归调用中,记录当前路径。
      • 当到达终点时,将当前路径保存到全局路径数组 allPaths 中。
    2. printAllPaths 函数

      • 遍历 allPaths 数组,输出每条路径的具体坐标。
    3. generateValidMaze 函数

      • 生成随机迷宫并确保其可解。
    4. 路径存储与释放

      • 使用动态分配内存存储路径节点,避免固定大小的限制。
      • 在路径保存后,释放当前路径的内存以节省空间。

    运行结果示例

    假设生成的迷宫如下:

    S 1 1 1 1 1 1 1 1 1
    0 1 1 0 1 1 1 1 1 1
    1 0 1 0 1 0 0 0 1 1
    1 0 1 0 1 0 1 0 1 1
    1 0 0 0 1 0 1 0 1 1
    1 1 1 0 1 0 1 0 1 1
    1 1 1 0 1 0 1 0 0 1
    1 1 1 0 0 0 1 1 1 1
    1 1 1 1 1 1 1 1 1 1
    1 1 1 1 1 1 1 1 1 E
    

    程序输出所有可行路径,例如:

    找到以下所有路径:
    路径 1:
    (1, 0) (2, 1) (3, 2) (4, 3) (5, 4) (6, 5) (7, 6) (8, 7) (9, 8) (10, 9)
    路径 2:
    (1, 0) (2, 1) (3, 2) (4, 3) (5, 4) (6, 5) (7, 6) (8, 7) (9, 8) (10, 9)
    ...
    

    重点总结

    • 核心算法:使用 DFS 遍历迷宫,记录所有可行路径。
    • 动态存储:通过动态分配内存存储路径,避免固定大小的限制。
    • 路径打印:输出所有路径的坐标,方便用户查看。
    评论

报告相同问题?

问题事件

  • 修改了问题 6月11日
  • 创建了问题 6月11日