1 条题解
-
0
#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
- 上传者