7-10 联通块的权
给出一个大小为n×m的网格矩阵,第i行第j列的单元格的权值为ai,j。
若某个单元格权值不为0且其上下左右相邻的单元格同样不为0,则其构成一个联通块。
求该矩阵联通块的最大权值。
输入格式:
输入的第一行给出一个整数T——表示测试用例的数量。
接下来对于每一组测试用例,第一行给出两个整数n,m,表示网格矩阵的大小。
接下来n行,每行m个整数ai,j——表示第i行第j列单元格的权值。
1≤T≤1000
1≤n,m≤1000
0≤ai,j≤1000
输出格式:
对于每一组测试用例,单独一行输出一个整数——表示该矩阵中联通块的最大权值。
输入样例:
4
3 3
1 2 0
3 4 0
0 0 5
1 1
0
5 5
1 1 1 1 1
1 0 0 0 1
1 0 5 0 1
1 0 0 0 1
1 1 1 1 1
3 3
0 1 1
1 0 1
1 1 1
输出样例:
10
0
16
7
问题描述
给定一个大小为n×m的网格矩阵,每个单元格都有一个权值。如果某个单元格的权值不为0且其上下左右相邻的单元格同样不为0,则这些单元格构成一个联通块。我们需要找到矩阵中所有联通块的最大权值之和。
解题思路
这个问题可以通过广度优先搜索(BFS)或深度优先搜索(DFS)来解决。我的解法采用了BFS算法,具体步骤如下:
- 初始化:读取输入数据,包括网格矩阵的大小和每个单元格的权值。
- 遍历网格:对于每个未被访问过且权值大于0的单元格,启动BFS搜索。
- BFS搜索:从当前单元格出发,探索其上下左右的相邻单元格,将符合条件的单元格加入队列,并累加它们的权值。
- 记录最大值:在每次BFS结束后,比较当前联通块的权值和与已知的最大值,更新最大值。
- 输出结果:处理完所有测试用例后,输出每个测试用例的最大联通块权值。
关键点分析
- BFS算法:适合处理网格中的联通块问题,能够有效地探索所有相连的单元格。
- 访问标记:使用一个标记数组
D
来记录哪些单元格已经被访问过,避免重复计算。 - 边界检查:在探索相邻单元格时,需要检查是否超出网格边界。
- 最大值更新:在每次BFS过程中实时更新当前联通块的权值和,并与全局最大值比较。
复杂度分析
- 时间复杂度:O(n×m),因为每个单元格最多被访问一次。
- 空间复杂度:O(n×m),用于存储网格矩阵和访问标记数组。
代码实现
#include<bits/stdc++.h>
using namespace std;
#define int long long
int b,c;
int C[1005][1005];
int D[1005][1005];
int xx[4]={0,1,0,-1};
int yy[4]={1,0,-1,0};
int snum=0;
int num;
struct node{
int x,y;
}now,nextt;
void bfs(int x,int y)
{
queue<node>q;
now.x=x;
now.y=y;
q.push(now);
D[x][y]=1;
num+=C[x][y];
C[x][y]=0;
snum=max(snum,num);
while(!q.empty())
{
now=q.front();
q.pop();
for(int i=0;i<4;i++)
{
int y1=now.y+yy[i];
int x1=now.x+xx[i];
if(y1>0&&y1<=c&&x1>0&&x1<=b)
{
if(D[x1][y1]==0&&C[x1][y1]>0)
{
D[x1][y1]=1;
num += C[x1][y1];
C[x1][y1]=0;
snum=max(snum,num);
nextt.x=x1;
nextt.y=y1;
q.push(nextt);
}
}
}
}
}
signed main()
{
int a;
cin>>a;
while(a--)
{
snum=0;
cin>>b>>c;
for(int i=1;i<=b;i++)
{
for(int j=1;j<=c;j++)
{
cin>>C[i][j];
D[i][j]=0;
}
}
for(int i=1;i<=b;i++)
{
for(int j=1;j<=c;j++)
{
if(C[i][j]>0&&D[i][j]==0)
{
num=0;
bfs(i,j);
}
}
}
cout<<snum<<endl;
}
return 0;
}
总结
希望这篇博客能够帮助大家理解如何用BFS解决联通块问题。如果有任何疑问或建议,欢迎在评论区留言讨论。