Uva572(DFS+联通集)

题目地址

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=838&page=show_problem&problem=513

题目分析

就是搜索一个二维数组里面的'@'联通集,并求联通集的个数,做法是:用二维数组存储输入的字符,然后找dfs()的第一个起点,因为不是有向图所以可以从二维数组的第一个'@'开始进行dfs()搜索。dfs()的写法就是递归,因为要求递归找到对应起点的所有子孙并标上序号,所以还需要一个idx[][]去存储每个'@'的所属连通集序号。dfs()写法中递归的条件也是需要注意的,具体的要求是:

  • 点在二维数组范围内
  • 点没有被标号为某个联通集序号
  • 点为'@'

代码:

#include <bits/stdc++.h>
using namespace std;

const int maxn = 210;
int m,n;
char buf[maxn][maxn];
int idx[maxn][maxn];

bool inside(int r,int c){
    if(r < 0 || r >= m || c < 0 || c >= n) return false;
    return true;
}
void dfs(int r,int c ,int id){
    idx[r][c] = id;
    for(int dr = -1;dr <= 1;dr++){
        for(int dc = -1;dc <= 1;dc++){
            if(dr != 0 || dc != 0){     //扫描的结点不是本身 
                if(inside(r+dr,c+dc) && idx[r+dr][c+dc] == 0 && buf[r+dr][c+dc] == '@')     //周边的结点满足条件则递归:1:不越界,2:没有被标号;3:为'@' 
                    dfs(r+dr,c+dc,id);
            }
        }
    }
}
int main(void){
    while(scanf("%d%d",&m,&n) == 2 && m && n){
        for(int i = 0;i < m;i++){
            scanf("%s",buf[i]);
        }
        
        memset(idx,0,sizeof(idx));
        int cnt = 0;
        for(int i = 0;i < m;i++){
            for(int j = 0;j < n;j++){
                if(buf[i][j] == '@' && idx[i][j] == 0)
                    dfs(i,j,++cnt);     //深度优先搜索 
            }
        }
        printf("%d\n",cnt);
    }
    return 0;
}

补充一种和刘汝佳不同的做法,不需要存储联通块的序号,更加简单:

#include <bits/stdc++.h>
using namespace std;

const int maxn = 210;
int m,n;
char buf[maxn][maxn];       

bool inside(int r,int c){
    if(r < 0 || r >= m || c < 0 || c >= n) return false;
    return true;
}

void dfs(int r,int c){
    buf[r][c] = '*';        //将遍历过的所有连通块全部变为*;就可以不用存储连通块序号的数组了
    
    //循环遍历移动8个方向 
    for(int dr = -1;dr <= 1;dr++){
        for(int dc = -1;dc <= 1;dc++){
            //判断(r+dr,c+dc)是不是在区域内,并且为油田 
            if(inside(r+dr,c+dc) && buf[r+dr][c+dc] == '@')
                dfs(r+dr,c+dc);
        }
    }
}

int main(void){
    while(scanf("%d%d",&m,&n) == 2 && m && n){
        for(int i = 0;i < m;i++){
            scanf("%s",buf[i]);
        }
        
        int cnt = 0;
        for(int i = 0;i < m;i++){
            for(int j = 0;j < n;j++){
                if(buf[i][j] == '@')
                {
                    dfs(i,j);     
                    cnt++;
                }
            }
        }
        printf("%d\n",cnt);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值