递归回溯——Oil Deposits

Oil Deposits

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 21383 Accepted Submission(s): 12319

Problem Description
The GeoSurvComp geologic survey company is responsible for detecting underground oil deposits. GeoSurvComp works with one large rectangular region of land at a time, and creates a grid that divides the land into numerous square plots. It then analyzes each plot separately, using sensing equipment to determine whether or not the plot contains oil. A plot containing oil is called a pocket. If two pockets are adjacent, then they are part of the same oil deposit. Oil deposits can be quite large and may contain numerous pockets. Your job is to determine how many different oil deposits are contained in a grid.

Input
The input file contains one or more grids. Each grid begins with a line containing m and n, the number of rows and columns in the grid, separated by a single space. If m = 0 it signals the end of the input; otherwise 1 <= m <= 100 and 1 <= n <= 100. Following this are m lines of n characters each (not counting the end-of-line characters). Each character corresponds to one plot, and is either *', representing the absence of oil, or@’, representing an oil pocket.

Output
For each grid, output the number of distinct oil deposits. Two different pockets are part of the same oil deposit if they are adjacent horizontally, vertically, or diagonally. An oil deposit will not contain more than 100 pockets.

Sample Input

1 1 
* 
3 5 
*@*@* 
**@** 
*@*@* 
1 8 
@@****@* 
5 5 
****@ 
*@@*@ 
*@**@ 
@@@*@ 
@@**@ 
0 0

Sample Output

0 
1
2 
2

题意:给定的n*m图中,有多少块区域,就是数组中的@,块的意思就是只要@周围八个位置有另一个@就把它们视为一块。
分析:这一题可以说是搜索中最基础的一题之一。挨个点搜索标记就行了。
我们可以这样解决这个问题,首先对图上所有位置均设置一个标记位,表示该位置是否已经被计算过,
且该标记仅对地图上为@的点有效。这样按从左到右,从上到下的顺序遍历地图上所有位置,
若遍历到@且该点未被标记,则与所有与其直接相邻或者间接相邻的@(周围八个位置)组成一个块,
该块即为一个我们需要计算的块,将该块中所有的@位置标记位以计算。这样,当所有的位置被遍历过后,
即得到了所需答案

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Oil_Deposit {

    static char maze[][]=new char[101][101];//保存地图信息
    static int go[][]={{1,0},{-1,0},{0,1},{0,-1},{1,1},{1,-1},{-1,-1},{-1,1}};//邻接点位置差值
    public static void main(String[] args) throws IOException {
        BufferedReader bf=new BufferedReader(new InputStreamReader(System.in));
        String str[]=bf.readLine().split(" ");
        int n=Integer.parseInt(str[0]);//行数
        int m=Integer.parseInt(str[1]);//列数
        for (int i = 0; i < n; i++) {//录入地图信息
            String temp=bf.readLine();
            maze[i]=temp.toCharArray();
        }
        //init mark 本来默认就是false
        int ans=0;//初始化块计数器
        for (int i = 0; i < n; i++) {//遍历图
            for (int j = 0; j < m; j++) {
                if (maze[i][j]=='@') {//遇到位置不为@,跳过
                    ans++;//计数器递增
                    dfs(i,j,n,m);//递归遍历与其直接或间接相邻的@
                }else {
                    continue;
                }
            }
        }
        System.out.println(ans);

    }
    public static void dfs(int x, int y,int n,int m) {
        for (int i = 0; i < go.length; i++) {//遍历8个节点
            maze[x][y]='*';//将已经遍历过的记为*代表不可被选用
            int nx=x+go[i][0];
            int ny=y+go[i][1];
            if (nx<0||nx>=n||ny<0||ny>=m) {
                continue;//超过地图边界,跳过
            }
            if (maze[nx][ny]=='*') {//遇到位置不为@,跳过
                continue;
            }
            dfs(nx, ny, n, m);//递归查询与之相邻的节点
        }
    }

}

如果你不习惯go[][]的写法,可以看这个版本。
关于边界的判断,放在主函数也行,或者dfs也行看个人习惯

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Oil_Deposit2 {

    static char maze[][]=new char[101][101];//保存地图信息
    public static void main(String[] args) throws IOException {
        BufferedReader bf=new BufferedReader(new InputStreamReader(System.in));
        String str[]=bf.readLine().split(" ");
        int n=Integer.parseInt(str[0]);//行数
        int m=Integer.parseInt(str[1]);//列数
        for (int i = 0; i < n; i++) {//录入地图信息
            String temp=bf.readLine();
            maze[i]=temp.toCharArray();
        }
        //init mark 本来默认就是false
        int ans=0;//初始化块计数器
        for (int i = 0; i < n; i++) {//遍历图
            for (int j = 0; j < m; j++) {
                if (maze[i][j]=='@') {//遇到位置不为@,跳过
                    ans++;//计数器递增
                    dfs(i,j,n,m);//递归遍历与其直接或间接相邻的@
                }
            }
        }
        System.out.println(ans);

    }
    public static void dfs(int x, int y,int n,int m) {
        if (x<0||x>=n||y<0||y>=m||maze[x][y]!='@') {//注意次序,maze[x][y]的判断首先要确定是合法下标
            return ;//超过地图边界,遇到不统计位置
        }else {
            maze[x][y]='*';//标记为不可选用
            dfs(x-1, y, n, m);
            dfs(x-1, y+1, n, m);
            dfs(x, y+1, n, m);
            dfs(x+1, y+1, n, m);
            dfs(x+1, y, n, m);
            dfs(x+1, y-1, n, m);
            dfs(x, y-1, n, m);
            dfs(x-1, y-1, n, m);            
        }
    }

}

这类将玲姐的点联合成一个块的算法有一个专门的名词——Flood Fill,它场作为某些算法的预处理方式使用。
用BFS也可以完成,但这种方式代码比较精简。
使用递归时候注意爆栈的问题。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值