有一矩形区域的城市中建筑了若干建筑物,如果某两个单元格有一个点相联系,则它们属于同一座建筑物。现在想在这些建筑物之间搭建一些桥梁,其中桥梁只能沿着矩形的方格的边沿搭建,如下图城市1有5栋建筑物,可以搭建4座桥将建筑物联系起来。城市2有两座建筑物,但不能搭建桥梁将它们连接。城市3只有一座建筑物,城市4有3座建筑物,可以搭建一座桥梁联系两栋建筑物,但不能与第三座建筑物联系在一起。
在输入的数据中的第一行包含描述城市的两个整数r 和c, 分别代表从北到南、从东到西的城市大小(1 <= r <= 50 and 1 <= c <= 50). 接下来的r 行, 每一行由c 个(“#”)和(“.”)组成的字符. 每一个字符表示一个单元格。“#”表示建筑物,“.”表示空地。
在输出的数据中有两行,第一行表示建筑物的数目。第二行输出桥的数目和所有桥的总长度。
样例1
3 5
#...#
..#..
#...#
样例2
3 5
##...
.....
....#
样例3
3 5
#.###
#.#.#
###.#
样例4:
3 5
#.#..
.....
....#
样例1
5
4 4
样例2
2
0 0
样例3
1
0 0
样例4
3
1 1
AC代码如下,根据题解思考后,我在代码中加上了相应的注释,以帮助理解。毕竟是人家的代码,所以还是要敲上20遍,才能彻底成为自己的。
/* 1002 搭桥 http://codevs.cn/problem/1002/ */ #include<cstdio> #include<iostream> #include<cstring> #include<cmath> #include<algorithm> using namespace std; char cc[60][60]; // 存储map int n, m; int ans = 0; // ans 记录合并后桥的数目 bool k[60][60]; int fa[4000]; // 并查集 fa int sum = 0; int t = 1; struct veda { int pre; int re; int val; }dis[100001]; int find(int x) { if (fa[x] == x) return x; return fa[x] = find(fa[x]); } // 递归调用 并查集合并相连的建筑物 void junk(int a, int b) { k[a][b] = 1; // 下面的方格 if (cc[a + 1][b] == '#' && k[a + 1][b] == 0) { fa[a*m + b] = find((a - 1)*m + b); // 合并 junk(a + 1, b); } //右 if (cc[a][b + 1] == '#'&&k[a][b + 1] == 0) { fa[(a - 1)*m + (b + 1)] = find((a - 1)*m + b); junk(a, b + 1); } // 上 if (cc[a - 1][b] == '#'&&k[a - 1][b] == 0) { fa[(a - 2)*m + b] = find((a - 1)*m + b); junk(a - 1, b); } // 左 if (cc[a][b - 1] == '#'&&k[a][b - 1] == 0) { fa[(a - 1)*m + b - 1] = find((a - 1)*m + b); junk(a, b - 1); } // 左上 if (cc[a - 1][b - 1] == '#'&&k[a - 1][b - 1] == 0) { fa[(a - 2)*m + b - 1] = find((a - 1)*m + b); junk(a - 1, b - 1); } // 右下 if (cc[a + 1][b + 1] == '#'&&k[a + 1][b + 1] == 0) { fa[a*m + b + 1] = find((a - 1)*m + b); junk(a + 1, b + 1); } //左下 if (cc[a + 1][b - 1] == '#'&&k[a + 1][b - 1] == 0) { fa[a*m + b - 1] = find((a - 1)*m + b); junk(a + 1, b - 1); } //右上 if (cc[a - 1][b + 1] == '#'&&k[a - 1][b + 1] == 0) { fa[(a - 2)*m + b + 1] = find((a - 1)*m + b); junk(a - 1, b + 1); } } int cmp(veda a, veda b) { if (a.val != 0 && b.val != 0) return a.val < b.val; if (a.val == 0) return false; if (b.val == 0) return true; } // 搭桥过程 每一个点 有6条线可以搭桥 // 本行 本列 紧挨着的行和列 共6个 void add(int a, int b) { for (int i = 1; i <= n; ++i) if (i != a&&cc[i][b] == '#') { sum++; dis[sum].pre = (a - 1)*m + b; // 桥的起点 坐标 (i,j)转换成为 i*m+j dis[sum].re = (i - 1)*m + b; // 桥的终点 坐标 dis[sum].val = abs(i - a) - 1; // 代表桥的长度 } for (int i = 1; i <= n; ++i) if (i != a&&cc[i][b + 1] == '#') { sum++; dis[sum].pre = (a - 1)*m + b; dis[sum].re = (i - 1)*m + b + 1; dis[sum].val = abs(i - a) - 1; } for (int i = 1; i <= n; ++i) if (i != a&&cc[i][b - 1] == '#') { sum++; dis[sum].pre = (a - 1)*m + b; dis[sum].re = (i - 1)*m + b - 1; dis[sum].val = abs(i - a) - 1; } for (int j = 1; j <= m; ++j) if (j != b&&cc[a][j] == '#') { sum++; dis[sum].pre = (a - 1)*m + b; dis[sum].re = (a - 1)*m + j; dis[sum].val = abs(j - b) - 1; } for (int j = 1; j <= m; ++j) if (j != b&&cc[a + 1][j] == '#') { sum++; dis[sum].pre = (a - 1)*m + b; dis[sum].re = a*m + j; dis[sum].val = abs(j - b) - 1; } for (int j = 1; j <= m; ++j) if (j != b&&cc[a - 1][j] == '#') { sum++; dis[sum].pre = (a - 1)*m + b; dis[sum].re = (a - 2)*m + j; dis[sum].val = abs(j - b) - 1; } } int main() { //freopen("in", "r", stdin); scanf("%d%d", &n, &m); // 1- n*m 表示每一个方格 fa置为其位置 for (int i = 1; i <= n*m; ++i) fa[i] = i; //输入 n行m列 for (int i = 1; i <= n; ++i) for (int j = 1; j <= m; ++j) cin >> cc[i][j]; // 并查集 合并 得到合并后的建筑物数量 for (int i = 1; i <= n; ++i) for (int j = 1; j <= m; ++j) if (cc[i][j] == '#') // 是'#' 且没有被访问过 { if (k[i][j] == 0) { k[i][j] = 1; ans++; junk(i, j); // 合并所有能 合并的建筑物 } } // 遍历# 进行搭桥工作 for (int i = 1; i <= n; ++i) for (int j = 1; j <= m; ++j) if (cc[i][j] == '#') { add(i, j); } sort(dis + 1, dis + sum + 1, cmp); // 按照距离从小到大排序 int g = 1; int rr = 0; // 桥的数目 int minn = 0; //桥的总长度 for (int i = 1; i <= sum; ++i) // ans个建筑 最多需要 ans-1 座桥 选择其中最短距离的ans-1个桥就行了 { if (g == ans) break; int x = find(dis[i].pre); int y = find(dis[i].re); if (find(x) != find(y)) // 如果这两个# 不在一个并查集中 才能算作一个有意义的桥 { fa[x] = y; // 将其合并 桥的数量 桥的长度 rr++; minn += dis[i].val; g++; } } printf("%d\n%d %d\n", ans, rr, minn); return 0; } /* 3 5 #...# ..#.. #...# 3 5 ##... ..... ....# 3 5 #.### #.#.# ###.# 3 5 #.#.. ..... ....# 5 4 4 2 0 0 1 0 0 3 1 1 */
版权声明:本文为博主原创文章,未经博主允许不得转载。
原文地址:http://blog.csdn.net/qq_26437925/article/details/48086651