油田 UVA - 572(DFS解法+BFS解法)

该博客详细介绍了如何使用深度优先搜索(DFS)和广度优先搜索(BFS)解决油田连通分量的问题。通过递归或队列遍历地图中的'@'符号,对油田进行分块计数。两种算法思路相似,都是从发现的未访问'@'开始,标记并访问其相邻的未访问单元格,直至所有连通的'@'都被赋予相同的分量编号。最终输出连通分块的数量。示例代码提供了两种解法的实现,并附带了测试用例。
摘要由CSDN通过智能技术生成

在这里插入图片描述题目链接: 油田.

分析与思考:
DFS解法:
         从每个"@“格子除法,递归遍历它周围的”@"格子。每访问一个格子时,就给它写上一个“连通分量编号”(即下面的idx数组),这样就可以在访问之前检查它是否已经有了编号,从而避免同一个格子访问多次。
BFS解法:
         思路与DFS解法类似,不过是把递归调用改为了队列调用。
使用二维数组对油田中每个点进行访问, 一旦遍历到@ ,且@没被访问过, 则将其入队进行BFS遍历,入队的所有@符号都设置为已被访问过。 遍历完成后cnt+1。

下面提供两种解法:

DFS解法:

import java.util.*;
//使用深度优先搜索找出图中的所有连通分量
public class test1 {
      static int n;
      static int m;
      static char[][] map = new char[100][100];//存储地图
      static int[][] idx = new int[100][100];//联通分量编号
      static void dfs(int r,int c,int id)
      {
          if(r<0||r>=m||c>=n||c<0) return;
          if(map[r][c]!='@'||idx[r][c]>0) return;
          idx[r][c] = id;
          for(int dr=-1;dr<=1;dr++)
          {
              for(int dc=-1;dc<=1;dc++)
              {
                  if(dr!=0||dc!=0)
                  {
                      dfs(r+dr,c+dc,id);
                  }
              }
          }
      }

    public static void main(String[] args) {
          Scanner in = new Scanner(System.in);
          m = in.nextInt();
          n = in.nextInt();
          for(int i=0;i<m;i++)
          {
            String s = in.next();
            map[i] = s.toCharArray();
          }
          int cnt = 0;
          for(int i=0;i<m;i++)
          {
              for(int j=0;j<n;j++)
              {
                  if(idx[i][j]==0&&map[i][j]=='@')
                  {
                      dfs(i,j,++cnt);
                  }
              }
          }
        System.out.println("连通分块数量为:" + cnt);
    }
}
/* 测试用例:
5 5
****@
*@@*@
*@**@
@@@*@
@@**@
 */

BFS解法:

import java.util.Scanner;
class Test2{
    static Scanner in = new Scanner(System.in);
    static int m;
    static int n;
    static char[][] map = new char[105][105];
    static boolean[][] vis = new boolean[105][105];

    static void BFS(int i,int j)
    {
        queue[] pq = new queue[105];//数组模拟队列
        int head = 1;
        int tail = 1;
        pq[tail] = new queue(i,j);
        vis[i][j] = true;
        tail++;
        while(head<tail)
        {
            for(int dr=-1;dr<=1;dr++)
            {
                for(int dc=-1;dc<=1;dc++)//双重for循环控制八个方向
                {
                    if(dr!=0||dc!=0)
                    {
                        int tx = pq[head].x + dr;
                        int ty = pq[head].y + dc;
                        if(tx<0||tx>=m||ty<0||ty>=n) continue;
                        if(!vis[tx][ty]&&map[tx][ty]=='@')
                        {
                            pq[tail] = new queue(tx,ty);
                            vis[tx][ty] = true;
                            tail++;
                        }
                    }
                }
            }
            head++;
        }
    }
    static class queue
    {
        public queue(int x, int y)
        {
            this.x = x;
            this.y = y;
        }
        int x;
        int y;
    }

    public static void main(String[] args) {
        m = in.nextInt();
        n = in.nextInt();
        for(int i=0;i<m;i++)
        {
            String s = in.next();
            map[i] = s.toCharArray();
        }
        int cnt = 0;
        for(int i=0;i<m;i++)
        {
            for(int j=0;j<n;j++)
            {
                if(!vis[i][j]&&map[i][j]=='@')
                {
                    BFS(i,j);
                    cnt++;
                }
            }
        }
        System.out.println("连通分块数量为:" + cnt);
        
    }
}
/* 测试用例:
5 5
****@
*@@*@
*@**@
@@@*@
@@**@
 */


总结:
上面的代码用了一个二重循环来找到当前格子的相邻8个格子,也可以用常量数组或者写8条DFS调用,同时这道题目的算法有个好听的名字:种子填充

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值