利用DFS算出有多少个连通图
- 2020 年 2 月 11 日
- 筆記
以下面一个题目为例,[题目链接]: 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("%dn", cnt); }