1 条题解

  • 0
    @ 2025-5-6 1:15:04

    题意分析

    题目要求计算博格人在迷宫中搜索并同化所有外星人的最小总移动成本。迷宫由字符矩阵表示,包含起点S、外星人A、可通行空地 和障碍物#。搜索群体可以分裂,总成本是所有群体移动步数之和。

    解题思路

    1. 图建模:将每个SA视为图中的顶点,顶点间的边权为两点间的最短路径长度。
    2. 最短路径计算:使用BFS计算每对顶点间的最短路径。
    3. 最小生成树:使用Prim算法计算连接所有顶点的最小生成树,其边权和即为最小总成本。

    实现步骤

    1. 输入处理:读取迷宫地图,标记所有SA的位置。
    2. BFS预处理:对每个SA点,使用BFS计算到其他点的最短路径。
    3. 构建图:用预处理的最短路径填充邻接矩阵。
    4. Prim算法:计算最小生成树的总权重。
    5. 输出结果:输出最小总成本。

    C++实现

    #include <iostream>
    #include <algorithm>
    #include <queue>
    #include <cstring>
    using namespace std;
    
    const int INF = 0x3f3f3f3f;
    const int MAXN = 55;
    
    struct Point {
        int x, y, step;
    };
    
    int n, x, y;
    char g[MAXN][MAXN];
    int map[MAXN*2][MAXN*2];
    int xy[MAXN][MAXN];
    bool vis[MAXN][MAXN];
    int dirx[4] = {0,1,0,-1};
    int diry[4] = {1,0,-1,0};
    
    void bfs(int sx, int sy) {
        queue<Point> q;
        memset(vis, 0, sizeof(vis));
        
        Point start = {sx, sy, 0};
        vis[sx][sy] = true;
        q.push(start);
        
        while (!q.empty()) {
            Point curr = q.front();
            q.pop();
            
            if (g[curr.y][curr.x] == 'A' || g[curr.y][curr.x] == 'S') {
                map[xy[curr.x][curr.y]][xy[sx][sy]] = curr.step;
            }
            
            for (int i = 0; i < 4; i++) {
                int nx = curr.x + dirx[i];
                int ny = curr.y + diry[i];
                if (!vis[nx][ny] && g[ny][nx] != '#') {
                    vis[nx][ny] = true;
                    q.push({nx, ny, curr.step + 1});
                }
            }
        }
    }
    
    int prim() {
        int dis[MAXN], ans = 0;
        bool visited[MAXN] = {false};
        
        for (int i = 0; i < n; i++) dis[i] = map[0][i];
        visited[0] = true;
        
        for (int i = 1; i < n; i++) {
            int min_dis = INF, next = -1;
            for (int j = 0; j < n; j++) {
                if (!visited[j] && dis[j] < min_dis) {
                    min_dis = dis[j];
                    next = j;
                }
            }
            ans += min_dis;
            visited[next] = true;
            for (int j = 0; j < n; j++) {
                if (!visited[j] && dis[j] > map[next][j]) {
                    dis[j] = map[next][j];
                }
            }
        }
        return ans;
    }
    
    int main() {
        int t;
        cin >> t;
        while (t--) {
            cin >> x >> y;
            cin.ignore();
            n = 0;
            
            for (int i = 0; i < y; i++) {
                cin.getline(g[i], MAXN);
                for (int j = 0; j < x; j++) {
                    if (g[i][j] == 'A' || g[i][j] == 'S') {
                        xy[j][i] = n++;
                    }
                }
            }
            
            memset(map, INF, sizeof(map));
            for (int i = 0; i < y; i++) {
                for (int j = 0; j < x; j++) {
                    if (g[i][j] == 'S' || g[i][j] == 'A') {
                        bfs(j, i);
                    }
                }
            }
            
            cout << prim() << endl;
        }
        return 0;
    }
    

    代码说明

    1. 数据结构

      • Point结构体记录坐标和步数
      • map数组存储顶点间的最短路径
      • xy数组记录特殊点(SA)的编号
    2. BFS函数

      • 计算从给定起点到其他特殊点的最短路径
      • 使用队列实现广度优先搜索
      • 更新邻接矩阵map
    3. Prim算法

      • 计算最小生成树
      • 维护dis数组记录当前最小距离
      • 使用贪心策略逐步扩展生成树
    4. 复杂度分析

      • BFS预处理:O(k×x×y)O(k \times x \times y)kk为特殊点数量
      • Prim算法:O(n2)O(n^2)nn为特殊点数量
      • 总体复杂度在题目限制范围内可行
    • 1