题目链接: 油田.
分析与思考:
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调用,同时这道题目的算法有个好听的名字:种子填充