【题目链接】
【题目考点】
1. 深搜、广搜:连通块
2. 图论:连通分量
3. 并查集
【解题思路】
解法1:深搜
解法2:广搜
尝试从每个顶点出发进行搜索(可以使用深搜获广搜),搜索一个格子周围的满足:在地图内,未访问过,与当前格子的数值不同的格子。一趟搜索标记的格子属于一个连通块(无向图连通分量)。
统计每个连通块中格子数量。
在询问某位置时,输出该位置所属的连通块的格子数量
解法2:并查集
将每个格子的二维坐标数据转为一维数据
如果网格有n列,则从1开始的坐标(x, y)可转为(x-1)*n+y。
每个格子是一个元素,每个连通块(连通分量)是一个集合。使用并查集合并相邻的数值不同的格子,同时统计每个格子中元素数量。
查询某格子时,输出该格子所在集合的元素数量
【题解代码】
解法1:深搜
#include<bits/stdc++.h>
using namespace std;
#define N 1005
char mp[N][N];
int n, m, ccNum[N*N], ccn;//ccNum[i]:连通分量i的节点数量,连通分量数量可以达到N*N ccn:最大连通分量数量
int vis[N][N];//vis[x][y]:(x, y)所在的连通分量编号
int dir[4][2] = {{0,1}, {0,-1}, {1,0}, {-1,0}};
void dfs(int sx, int sy)
{
for(int i = 0; i < 4; ++i)
{
int x = sx+dir[i][0], y = sy+dir[i][1];
if(x >= 1 && x <= n && y >= 1 && y <= n && vis[x][y] == 0 && mp[x][y] != mp[sx][sy])
{
vis[x][y] = ccn;
ccNum[ccn]++;
dfs(x, y);
}
}
}
int main()
{
int x, y;
cin >> n >> m;
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= n; ++j)
cin >> mp[i][j];
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= n; ++j)
if(vis[i][j] == 0)
{
vis[i][j] = ++ccn;
ccNum[ccn]++;
dfs(i, j);
}
while(m--)
{
cin >> x >> y;
cout << ccNum[vis[x][y]] << endl;
}
return 0;
}
解法2:广搜
#include<bits/stdc++.h>
using namespace std;
#define N 1005
struct Pair
{
int x, y;
Pair(){}
Pair(int a, int b):x(a), y(b){}
};
char mp[N][N];
int n, m, ccNum[N*N], ccn;//ccNum[i]:连通分量i的节点数量,连通分量数量可以达到N*N ccn:最大连通分量数量
int vis[N][N];//vis[x][y]:(x, y)所在的连通分量编号
int dir[4][2] = {{0,1}, {0,-1}, {1,0}, {-1,0}};
void bfs(int sx, int sy)
{
queue<Pair> que;
vis[sx][sy] = ++ccn;
ccNum[ccn]++;
que.push(Pair(sx, sy));
while(que.empty() == false)
{
Pair u = que.front();
que.pop();
for(int i = 0; i < 4; ++i)
{
int x = u.x+dir[i][0], y = u.y+dir[i][1];
if(x >= 1 && x <= n && y >= 1 && y <= n && vis[x][y] == 0 && mp[x][y] != mp[u.x][u.y])
{
vis[x][y] = ccn;
ccNum[ccn]++;
que.push(Pair(x, y));
}
}
}
}
int main()
{
int x, y;
cin >> n >> m;
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= n; ++j)
cin >> mp[i][j];
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= n; ++j)
if(vis[i][j] == 0)
bfs(i, j);
while(m--)
{
cin >> x >> y;
cout << ccNum[vis[x][y]] << endl;
}
return 0;
}
解法3:并查集
#include<bits/stdc++.h>
using namespace std;
#define N 1005
char mp[N][N];
int n, m, fa[N*N], ccNum[N*N];
int num(int x, int y)//把二维数据转为一维数据
{
return (x-1)*n+y;
}
void init(int n)
{
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= n; ++j)
{
fa[num(i,j)] = num(i, j);
ccNum[num(i, j)] = 1;
}
}
int find(int x)
{
if(x == fa[x])
return x;
return fa[x] = find(fa[x]);
}
void merge(int x, int y)
{
int u = find(x), v = find(y);
if(u != v)
{
fa[u] = v;
ccNum[v] += ccNum[u];
}
}
int main()
{
int x, y;
cin >> n >> m;
init(n);
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= n; ++j)
cin >> mp[i][j];
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= n; ++j)
{
if(j+1 <= n && mp[i][j] != mp[i][j+1])
merge(num(i, j), num(i, j+1));
if(i+1 <= n && mp[i][j] != mp[i+1][j])
merge(num(i, j), num(i+1, j));
}
while(m--)
{
cin >> x >> y;
cout << ccNum[find(num(x, y))] << endl;
}
return 0;
}