算法提升并查集终章篇

发布于:2025-08-13 ⋅ 阅读:(19) ⋅ 点赞:(0)

历时1周的学习和总结,今天将结束并查集的学习,明天将会开启新的篇章。学习并解决关于树的相关问题和内容。

问题描述

鸡哥正在参与一场精彩的冒险活动,这个活动的场地是一个巨大的迷宫,由 N×M 个不同的房间组成,每个房间都恰好有一个彩色大珠子。每个房间都有一个独特的魔法级别,魔法级别由一个整数表示,不同的房间魔法级别也不同。

每个珠子都被施加了一个魔法,它们会自动移动。珠子的移动规则如下:

  • 如果当前房间的魔法级别比所有相邻房间(最多有 8 个)的魔法级别都小,那么珠子就会停在这个房间。
  • 否则,珠子会移动到魔法级别最小的相邻房间。

鸡哥对这个迷宫非常好奇,他想知道最后每个房间里会有多少珠子。作为他的朋友,你能帮他解答这个问题吗?

输入格式

输入的第一行包含两个整数 N 和 M(1≤N,M≤200)。

接下来的 N 行,每行包含 M个整数,代表每个房间的魔法级别。魔法级别的范围在 0∼105 之间,且每个房间的魔法级别都是独特的。

输出格式

输出 N行,每行包含 M个整数。第 i 行的第 j 个数应该表示最后房间 (i,j) 里的珠子数量。

输入案例:

3 3
1 2 3
4 5 6
7 8 9

输出案例:

9 0 0
0 0 0
0 0 0

代码部分:

#include<bits/stdc++.h>
using namespace std;
#define c(i,j) (i)*m+j
int m,n,b[100005],a[100005];
int find(int x){
  return x==b[x]?x:(b[x]=find(b[x]));
}
int main(){
  cin>>n>>m;
  for (int i=0;i<n;i++){
    for (int j=0;j<m;j++){
      b[c(i,j)]=c(i,j);
      cin>>a[c(i,j)];
    }
  }
  for(int i=0;i<n;i++)
   for(int j=0;j<m;j++)
   {int h=c(i,j);
     for(int x=i-1;x<=i+1;x++)
      for(int y=j-1;y<=j+1;y++)
      {
        if(x<0||x>=n||y<0||y>=m)continue;
        if(a[c(x,y)]<a[h])h=c(x,y);
      }
      b[c(i,j)]=find(b[h]);
   }
   memset(a,0,sizeof(a));
  for (int i=0;i<n*m;i++){
    a[find(i)]++;
  }
  for (int i=0;i<n*m;i++){
    cout<<a[i]<<((i+1)%m==0?'\n':' ');
  }
  return 0;
}

这道题的关键是在

for (int i = 0; i < n; i++) {
    for (int j = 0; j < m; j++) {
        int h = c(i,j);  // 当前房间的一维索引
        // 检查 8 个相邻房间(包括自己)
        for (int x = i-1; x <= i+1; x++) {
            for (int y = j-1; y <= j+1; y++) {
                if (x < 0 || x >= n || y < 0 || y >= m) continue;  // 越界跳过
                if (a[c(x,y)] < a[h]) h = c(x,y);  // 找到魔法级别最小的相邻房间
            }
        }
        b[c(i,j)] = find(b[h]);  // 合并到最小魔法级别的房间
    }
}
  • 遍历每个房间 (i,j)

    • 检查其 8 邻域(包括自身)的魔法级别。

    • 找到 魔法级别最小的房间 h

    • 将当前房间的父节点指向 h 的根节点(find(b[h])),表示珠子会移动到 h

理解了这个部分就可以更好地理解了这段代码所表示的相关内容。

好了这部分分享就到这里,希望能对大家有所帮助,后续也将继续进行相关内容的分享和学习,希望大家可以多多关注,后续再见


网站公告

今日签到

点亮在社区的每一天
去签到