现在的位置: 首页 > 综合 > 正文

hdu1198 并查集

2013年05月13日 ⁄ 综合 ⁄ 共 1712字 ⁄ 字号 评论关闭

题目:Farm Irrigation

这题很不错的,给的图片让人想不到是并查集,我第一次做的时候用dfs()过的,最近在看并查集,才知道并查集也可以做。关键在于如何建图,如何找到相连关系。对每张图片分析就会知道,每块地的水管都是在中间,分为上、下、左、右四个方向可以通水,分两种模式,一种水平相邻,一种竖直相邻,判断他们能不能相通,先预处理得到每两个字符所代表的土地的关系,读入数据后,对应处理,将每块地都编一个标号,就抽象出并查集模型了,最后判断一下有几个点,它的根节点是它自己,就能找到最少需要的水源了。这也是并查集应用之一:判断有几个不相交的集合。

 

代码

#include<stdio.h>
#include
<string.h>

int up[8], down[8], right[8], left[8];
int rank[2504], bin[2504];
char map[54][54];
char mat1[100][100]; // 上下相连
char mat2[100][100]; // 左右相连
void prepare()
{
int i, j;
up[
0] = 'A'; up[1] = 'B'; up[2] = 'E'; up[3] = 'G'; up[4] = 'H'; up[5] = 'J'; up[6] = 'K';
down[
0] = 'C'; down[1] = 'D'; down[2] = 'E'; down[3] = 'H'; down[4] = 'I'; down[5] = 'J'; down[6] = 'K';
left[
0] = 'A'; left[1] = 'C'; left[2] = 'F'; left[3] = 'G'; left[4] = 'H'; left[5] = 'I'; left[6] = 'K';
right[
0] = 'B'; right[1] = 'D'; right[2] = 'F'; right[3] = 'G'; right[4] = 'I'; right[5] = 'J'; right[6] = 'K';
memset(mat1,
0, sizeof(mat1));
memset(mat2,
0, sizeof(mat2));
for (i = 0; i <= 6; i++){
for (j = 0; j <= 6; j++){
mat1[down[i]][up[j]]
= 1;
mat2[right[i]][left[j]]
= 1;
}
}
}

int find(int x){
if (x != bin[x]){
return bin[x] = find(bin[x]);
}
return x;
}

void merge(int x, int y){
int fx, fy;
fx
= find(x);
fy
= find(y);

if (fx != fy){
if (rank[fx] > rank[fy]){
bin[fy]
= fx;
}
else if (rank[fx] < rank[fy]){
bin[fx]
= fy;
}
else{
bin[fx]
= fy;
rank[fy]
++;
}
}
}

int main()
{
int M, N, i, j, t1, t2, cnt;
prepare();
while (scanf("%d%d", &M, &N) != EOF){
if (M == -1 && N == -1) break;
for (i = 0; i < M; i++){
scanf(
"%s", map[i]);
}

for (i = 0; i <= M * N; i++){
bin[i]
= i;
rank[i]
= 0;
}
for (i = 0; i < M; i++){
for (j = 0; j < N; j++){
if (j < N - 1 && mat2[map[i][j]][map[i][j+1]] == 1){
t1
= i * N + j;
t2
= i * N + j + 1;
merge(t1, t2);
}

if (i < M - 1 && mat1[map[i][j]][map[i + 1][j]] == 1){
t1
= i * N + j;
t2
= (i + 1) * N + j;
merge(t1, t2);
}
}
}

cnt
= 0;
for (i = 0; i < M * N; i++){
if (bin[i] == i){
cnt
++;
}
}

printf(
"%d\n", cnt);
}
return 0;
}

这里用的递归法压缩路径,感觉也挺好的,代码很短,以前都是用非递归形式。在合并的时候,按秩合并很重要,每次合并,总把深度小的树合并到深度大的树里面,以防止树退化成链。这样可以减少树的深度,使得查找时间很均匀,更高效的查找。

 

 

抱歉!评论已关闭.