1 条题解

  • 0
    @ 2026-6-14 9:18:56
    #include <iostream>
    #include <vector>
    #include <algorithm>
    #include <cstdlib>  // for abs
    
    using namespace std;
    
    // 并查集相关操作(优化版)
    class UnionFind {
    private:
        vector<int> parent;
        vector<int> rank;  // 用于路径压缩优化
        
    public:
        UnionFind(int n) {
            parent.resize(n);
            rank.resize(n, 0);
            for (int i = 0; i < n; ++i) {
                parent[i] = i;
            }
        }
    
        // 路径压缩优化的find
        int find(int x) {
            if (x!= parent[x]) {
                parent[x] = find(parent[x]);
            }
            return parent[x];
        }
    
        // 按秩合并优化
        void unionSet(int x, int y) {
            int rootX = find(x);
            int rootY = find(y);
            if (rootX == rootY) return;
            
            if (rank[rootX] < rank[rootY]) {
                parent[rootX] = rootY;
            } else {
                parent[rootY] = rootX;
                if (rank[rootX] == rank[rootY]) {
                    rank[rootX]++;
                }
            }
        }
        
        // 检查是否所有节点都已连通(只需要检查连通分量数量是否为1)
        bool isConnected(int components) {
            return components == 1;
        }
    };
    
    // 边结构体
    struct Edge {
        int u, v;  // 直接存储节点索引,避免重复计算
        int cost;
        Edge(int _u, int _v, int _c) : u(_u), v(_v), cost(_c) {}
    };
    
    // 比较函数,用于按cost从小到大排序
    bool compareEdge(const Edge& e1, const Edge& e2) {
        return e1.cost < e2.cost;
    }
    
    int main() {
        ios::sync_with_stdio(false);  // 加速输入输出
        cin.tie(nullptr);
        
        int m, n;
        cin >> m >> n;
        int totalNodes = m * n;
        
        if (totalNodes <= 1) {  // 特殊情况处理
            cout << 0 << endl;
            return 0;
        }
        
        UnionFind uf(totalNodes);
        int components = totalNodes;  // 初始连通分量数量为节点总数
        
        // 标记已存在的边
        vector<vector<bool>> horizontalEdge(m+1, vector<bool>(n, false));
        vector<vector<bool>> verticalEdge(m, vector<bool>(n+1, false));
        
        // 处理已有的连线
        int x1, y1, x2, y2;
        while (cin >> x1 >> y1 >> x2 >> y2) {
            // 检查坐标有效性
            if (x1 < 1 || x1 > m || y1 < 1 || y1 > n ||
                x2 < 1 || x2 > m || y2 < 1 || y2 > n) {
                break;
            }
            
            // 确定边的类型并标记
            if (x1 == x2 && abs(y1 - y2) == 1) {  // 横向边
                int x = x1;
                int y = min(y1, y2);
                horizontalEdge[x][y] = true;
            } else if (y1 == y2 && abs(x1 - x2) == 1) {  // 纵向边
                int x = min(x1, x2);
                int y = y1;
                verticalEdge[x][y] = true;
            }
            
            // 合并节点并更新连通分量数量
            int node1 = (x1 - 1) * n + y1 - 1;
            int node2 = (x2 - 1) * n + y2 - 1;
            if (uf.find(node1)!= uf.find(node2)) {
                uf.unionSet(node1, node2);
                components--;
            }
        }
    
        // 构建所有可能的边(除了已有的连线)
        vector<Edge> edges;
        edges.reserve(2 * m * n);  // 预分配空间,避免多次扩容
        
        // 添加纵向边(向下)
        for (int i = 1; i < m; ++i) {
            for (int j = 1; j <= n; ++j) {
                if (!verticalEdge[i][j]) {
                    int u = (i - 1) * n + j - 1;
                    int v = i * n + j - 1;
                    edges.emplace_back(u, v, 1);
                }
            }
        }
        
        // 添加横向边(向右)
        for (int i = 1; i <= m; ++i) {
            for (int j = 1; j < n; ++j) {
                if (!horizontalEdge[i][j]) {
                    int u = (i - 1) * n + j - 1;
                    int v = (i - 1) * n + j;
                    edges.emplace_back(u, v, 2);
                }
            }
        }
    
        // 按cost从小到大排序所有边
        sort(edges.begin(), edges.end(), compareEdge);
    
        int minCost = 0;
        // 依次处理边,构建最小生成树
        for (const Edge& e : edges) {
            if (uf.find(e.u)!= uf.find(e.v)) {
                uf.unionSet(e.u, e.v);
                minCost += e.cost;
                components--;
                
                // 所有节点已连通,提前退出
                if (uf.isConnected(components)) {
                    break;
                }
            }
        }
    
        cout << minCost << endl;
    
        return 0;
    }
    • 1

    信息

    ID
    397
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    12
    已通过
    2
    上传者