[C] 深度优先搜索解决连通块/染色问题——求岛的个数

本文通过一个宝岛探险的问题实例,介绍了如何使用深度优先搜索(DFS)来解决二维矩阵中连通块的数量问题。在C语言实现的解题过程中,通过染色法遍历矩阵,遇到未染色的陆地区域就进行DFS搜索,并更新连通块计数。最终,通过计算染色数的绝对值得到小岛的数量。同时,文章还提及了BFS在求解最大连通面积中的应用。
摘要由CSDN通过智能技术生成

本文介绍用DFS解决连通块个数问题

有关dfs的介绍见另外一篇:不撞南墙不回头——深度优先搜索

例题

宝岛探险

题目描述

一个小岛由一个主岛和一些复附属岛屿组成,该岛使用一个二维矩阵表示,其中数字表示海拔,0表示海洋,1~9表示陆地。探险家乘坐飞机降落在(6,8)处,现在需要统计探险家降落的地图的小岛数量,我们将探险家降落点上下左右相连接的陆地视作同一个岛屿。

本文介绍DFS的解法,如果想了解用BFS解最大连通面积,看另一篇文章:层层递进——C语言实现广度优先搜索


测试样例:
10 10 6 8
1 2 1 0 0 0 0 0 2 3
3 0 2 0 1 2 1 0 1 2
4 0 1 0 1 2 3 2 0 1
3 2 0 0 0 1 2 4 0 0
0 0 0 0 0 0 1 5 3 0
0 1 2 1 0 1 5 4 3 0
0 1 2 3 1 3 6 2 1 0
0 0 3 4 8 9 7 5 0 0
0 0 0 3 7 8 6 0 1 2
0 0 0 0 0 0 0 0 1 0
样例输出
4

解题思路

  • 这里startxstarty是多余的,请注意。
  • 这次要定义一个num,初始值为0,每次更换颜色之前-1,表示当前的颜色。
  • 对于每个点进行一次遍历,当这个点不是海洋并且没有被染色(值大于零)时,对这个点进行dfs搜索,将这个点所连通的地方全部染成一个“色”就是同一个数(这个时候被染色了,就是负值了~)
  • num取绝对值,就是岛的个数了。

题解

#include<stdio.h>
struct note
{
    int x;
    int y;
};
struct note que[400];
int head, tail;
int a[200][200];//地图
int book[200][200];
int next[4][2] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
int max = 0;
int sum = 0;
int n, m, startx, starty;

void dfs(int x, int y, int color)
{
    int k;
    int tx, ty;
    a[x][y] = color; // 对本格子染色
    for (k = 0; k < 4; k++)
    {
        tx = x + next[k][0];
        ty = y + next[k][1];
        if (tx < 1 || tx > n || ty < 1 || ty > m)
            continue;
        if (a[tx][ty] > 0 && book[tx][ty] == 0)
        {
            sum++;
            book[tx][ty] = 1;
            dfs(tx, ty, color);
        }
    }
    return;
}


int main()
{
    int i, j;
    int num = 0;
    scanf("%d %d %d %d", &n, &m, &startx, &starty);
    for (i = 1; i <= n; i++)
        for (j = 1; j <= m; j++)
            scanf("%d", &a[i][j]);

    for (i = 1; i <= n; i++)
    {
        for (j = 1; j <= m; j++)
        {
            if (a[i][j] > 0)
            {
                num--;// num表示色号,并且是负数
                book[i][j] = 1;
                sum = 1;
                dfs(i, j, num);
                if (sum > max)
                {
                    max = sum;
                }
            }
        }
    }
    for (i = 1; i <= n; i++)
    {
        for (j = 1; j <= m; j++)
        {
            printf("%3d", a[i][j]);
        }
        printf("\n");
    }
    printf("有%d个小岛\n", -num);
    printf("最大的岛的面积是%d\n", max);
    return 0;
}

/*
10 10 6 8
1 2 1 0 0 0 0 0 2 3
3 0 2 0 1 2 1 0 1 2
4 0 1 0 1 2 3 2 0 1
3 2 0 0 0 1 2 4 0 0
0 0 0 0 0 0 1 5 3 0
0 1 2 1 0 1 5 4 3 0
0 1 2 3 1 3 6 2 1 0
0 0 3 4 8 9 7 5 0 0
0 0 0 3 7 8 6 0 1 2
0 0 0 0 0 0 0 0 1 0

*/

运行结果:
在这里插入图片描述

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值