以下面一个题目为例,[题目链接]: https://www.luogu.com.cn/problem/P4961
题目中涉及求出八联通图的个数,这里给出这步的代码:
memset(vis, 0, sizeof(vis));
int cnt = 0;
for(int i = 0; i < n; i++)
{
for(int j = 0; j < m; j++)
{
if(!bomb[i][j] && !vis[i][j])
{
++cnt;
vis[i][j] = 1;
dfs(i, j);
}
}
}
void dfs(int x, int y)
{
for(int i = 0; i < 8; i++)
{
int xx = x + dx[i];
int yy = y + dy[i];
if(xx >= 0 && xx < n && yy >= 0 && yy < m && !vis[xx][yy] && !bomb[xx][yy])
{
vis[xx][yy] = 1;
dfs(xx, yy);
}
}
}
上面介绍的是求八连通图的个数,类似,求四联通图的个数也是相似的做法,只需把dx,dy数组变一变即可。
注意:四连通图也是八联通图,也就是说一个格的也行。
下面给出关于那道题目的代码:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 2000;
int n, m;
int dx[] = {0, 0, -1, -1, -1, 1, 1, 1};
int dy[] = {1, -1, 0, 1, -1, 0, 1, -1};
int bomb[maxn][maxn], vis[maxn][maxn];
void dfs(int x, int y)
{
for(int i = 0; i < 8; i++)
{
int xx = x + dx[i];
int yy = y + dy[i];
if(xx >= 0 && xx < n && yy >= 0 && yy < m && !vis[xx][yy] && !bomb[xx][yy])
{
vis[xx][yy] = 1;
dfs(xx, yy);
}
}
}
int main()
{
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
scanf("%d %d", &n, &m);
for(int i = 0; i < n; i++)
{
for(int j = 0; j < m; j++)
{
scanf("%d", &bomb[i][j]);
if(bomb[i][j])
bomb[i][j] = -1;
}
}
for(int i = 0; i < n; i++)
{
for(int j = 0; j < m; j ++)
{
if(bomb[i][j] == -1)
continue;
for(int ans = 0; ans < 8; ans++)
{
int xx = dx[ans] + i;
int yy = dy[ans] + j;
if(xx >= 0 && xx < n && yy >= 0 && yy < m && bomb[xx][yy] == -1)
++bomb[i][j];
}
}
}
memset(vis, 0, sizeof(vis));
int cnt = 0;
for(int i = 0; i < n; i++)
{
for(int j = 0; j < m; j++)
{
if(!bomb[i][j] && !vis[i][j])
{
++cnt;
vis[i][j] = 1;
dfs(i, j);
}
}
}
for(int i = 0; i < n; i++)
{
for(int j = 0; j < m; j++)
{
if(bomb[i][j] != 0 && bomb[i][j] != -1)
{
int flag = 0;
for(int k = 0; k < 8; k++)
{
int xx = i + dx[k];
int yy = j + dy[k];
if(xx < 0 || xx >= n || yy < 0 || yy >= m)
continue;
if(xx >= 0 && xx < n && yy >= 0 && yy < m && bomb[xx][yy] == 0)
{
flag = 1;
break;
}
}
if(!flag)
++cnt;
}
}
}
printf("%d\n", cnt);
}