黑白图像(DFS)

输入一个n*n的黑白图像(1表示黑色,0表示白色),任务是统计其中八连块的个数。如果两个黑格子有公共边或者公共顶点,就说它们属于同一个八连块。如图6-11所示的图形有3个八连块。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

图6-11  拥有3个八连块的黑白图形

【分析】

用递归求解:从每个黑格子出发,递归访问它所有的相邻黑格。

int mat[MAXN][MAXN], vis[MAXN][MAXN];
void dfs(int x, int y) {
  if(!mat[x][y] || vis[x][y])   return;     // 曾经访问过这个格子,或者当前格子是白色
  vis[x][y] = 1;                          // 标记(x,y)已访问过
  dfs(x-1,y-1); dfs(x-1,y); dfs(x-1,y+1);
  dfs(x-1,y);               dfs(x,y+1);
  dfs(x+1,y-1); dfs(x+1,y); dfs(x+1,y+1); // 递归访问周围的八个格子
}
这里,黑格(x,y)的mat[x][y]为1,白格为0。为了避免同一个格子访问多次,用标志vis[x][y]记录格子(x,y)是否访问过。在输入之前,在迷宫的外面加上一圈虚拟的白格子,见下面的程序。
memset(mat, 0, sizeof(mat)); //所有格子都初始化为白色,包括周围一圈的虚拟格子
memset(vis, 0, sizeof(vis));  // 所有格子都没有访问过
scanf("%d", &n);
for(int i = 0; i < n; i++) {
    scanf("%s", s);
    for(int j = 0; j < n; j++)
      mat[i+1][j+1] = s[j]-'0'; // 把图像往中间移动一点,空出一圈白格子
}


 

接下来,只需不断找黑格,然后调用dfs。从它出发寻找八连块:

int count = 0;
for(int i = 1; i <= n; i++)
   for(int j = 1; j <= n; j++)
     if(!vis[i][j] && mat[i][j]) { count++; dfs(i,j); } 
//找到没有访问过的黑格
printf("%d
", count);


 

完整的程序如下:

#include <stdio.h>
#include <string.h>
const int MAXN = 1000;
int n;

int mat[MAXN][MAXN], vis[MAXN][MAXN];
void dfs(int x, int y) {
   
  if(!mat[x][y] || vis[x][y])   return; //曾经访问过这个格子,或者当前
格子是白色
vis[x][y] = 1;                        // 标记(x,y)已访问过
  dfs(x-1,y-1); dfs(x-1,y); dfs(x-1,y+1);
  dfs(x-1,y);               dfs(x,y+1);
  dfs(x+1,y-1); dfs(x+1,y); dfs(x+1,y+1); // 递归访问周围的八个格子
}

int main() {
  char s[MAXN + 10];
  memset(mat, 0, sizeof(mat));  // 所有格子都初始化为白色,包括周围
一圈的虚拟格子
  memset(vis, 0, sizeof(vis));  // 所有格子都没有访问过
  scanf("%d", &n);
  for(int i = 0; i < n; i++) {
    scanf("%s", s);
    for(int j = 0; j < n; j++)
      mat[i+1][j+1] = s[j]-'0'; // 把图像往中间移动一点,空出一圈白格子
  }
  int count = 0;
  for(int i = 1; i <= n; i++)
    for(int j = 1; j <= n; j++)
      // 找到没有访问过的黑格
      if(!vis[i][j] && mat[i][j]) { count++; dfs(i,j); } 
  printf("%d
", count);
  return 0;
}


 

上面的函数dfs就是深度优先遍历(Depth-FirstSearch,DFS)的算法,DFS和BFS一样,都是从一个结点出发,按照某种特定的次序访问图中的其他特点。不同的是,BFS使用队列来存放待扩展结点,而DFS使用的是栈。

附:我自己理解后敲的代码:

#include <stdio.h>
#include <string.h>
#include<algorithm>
#include<iostream>
#define M  1020
using namespace std;
int n;
int i,j;
char map[M][M];
void dfs(int x,int y)
{

    if(map[x][y]!='1'||x<0||y<0||x>=n||y>=n)
        return; //曾经访问过这个格子,或者当前格子是白色
    else
    {
        map[x][y] = '0';                        // 标记(x,y)已访问过
        dfs(x-1,y-1);
        dfs(x-1,y+1);
        dfs(x-1,y);
        dfs(x,y+1);
        dfs(x,y-1);
        dfs(x+1,y-1);
        dfs(x+1,y);
        dfs(x+1,y+1); // 递归访问周围的八个格子
    }
}

int main()
{
    memset(map, 0, sizeof(map));  // 所有格子都没有访问过
    scanf("%d", &n);
    for(i=0; i<n; i++)
        for(j=0; j<n; j++)
            cin>>map[i][j];

    int count = 0;
    for(i = 0; i <n; i++)
        for(j = 0; j <n; j++)
        {
            // 找到没有访问过的黑格
            if(map[i][j]=='1')
            {
                dfs(i,j);
                count++;
            }
        }
    printf("%d
", count);
    return 0;
}
/*
6
100100
001010
000000
110000
111000
010100
*/


 

原文地址:https://www.cnblogs.com/dyllove98/p/3226233.html