1 条题解

  • 3

    考查连通块的个数,我们有两种方法解决:

    1. 搜索
    2. 并查集

    奈何本人并查集学魔怔了,所以这一道题着重讲解并查集。

    并查集

    思路分析

    对于一个 n×mn \times m 的矩阵 martixmartix,如果 martixi,jmartix_{i,j}. ,则和左边以及上边的合并(如果可能的话)(请读者自行思考为何只要合并两个方向)。 合并完后,查询有多少个集合即可。

    代码实现

    #include<bits/stdc++.h>
    using namespace std;
    int fa[400005],n,m;
    char martix[205][205];
    int find(int x){//并查集模版:查询、合并
    	return x==fa[x]?x:fa[x]=find(fa[x]);
    }
    void merge(int x,int y){
    	fa[find(x)]=find(y);
    }
    int change(int i,int j){//把二维的转成一维的
    	return i*m+j;
    }
    void init(int x){//并查集初始化
    	for(int i=0;i<x;i++){
    		fa[i]=i;
    	}
    }
    int main(){
    	freopen("water.in","r",stdin);
    	freopen("water.out","w",stdout);
    	cin>>n>>m;
    	init(n*m);
    	for(int i=0;i<n;i++){//输入
    		for(int j=0;j<m;j++){
    			cin>>martix[i][j];
    		}
    	}
    	for(int i=0;i<n;i++){
    		for(int j=0;j<m;j++){
    			if(martix[i][j]=='#')	continue;//如果是陆地,pass
    			if(i>0){//如果不在左边界
    				if(martix[i-1][j]=='.')//(防RE),且左边有水		
    					merge(change(i,j),change(i-1,j));//合并
    			}
    			if(j>0){//如果不在上边界
    				if(martix[i][j-1]=='.')		//且上边有水		
    					merge(change(i,j),change(i,j-1));//合并
    			}
    		}
    	}
    	int cnt=0;
    	for(int i=0;i<n;i++){//统计
    		for(int j=0;j<m;j++){
    			if(martix[i][j]=='#')	continue;
    			if(fa[change(i,j)]==change(i,j))	cnt++;
                 //如果fa[i]==i,说明是一个集合,统计
    		}
    	}
    	cout<<cnt;
    	return 0;
    }
    

    搜索

    思路

    1. 定义 visvis 记录访问,函数(函数名自拟),参数为矩阵、xxyy
    2. 如果越界或不是水或已访问,退出。
    3. visx,yvis_{x,y} 设置成 11
    4. 四个方向查找。

    代码

    思路这么详细了,相信各位不需要。

    总结

    难度:黄(普及 ~ 提高-)。

    最后,看到这了,点个赞吧,写代码不容易!

    • @ 2024-10-10 12:43:58
      #include<iostream>
      using namespace std;
      int main()
      {
       cout<<"牛逼\n";
       return 0;
      }
      
  • 1

信息

ID
775
时间
1000ms
内存
256MiB
难度
9
标签
(无)
递交数
37
已通过
2
上传者