24 lines of code AC_Oil Deposits UVA-572 (DFS solution + BFS solution + video explanation)

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.



Analysis and thinking:

Compared with the standard search template question, this question has been modified to find the number of connected blocks. This type of algorithm has a nice name: seed filling .

DFS solution:
Divide from each "@" grid, recursively traverse the "@" grids around it. Each time a grid is accessed, a "connected component number" (ie the idx array below) is written to it, so that you can check whether it has a number before accessing it, so as to avoid multiple accesses to the same grid.

BFS solution: The
idea is similar to the DFS solution, but the recursive call is changed to a queue call.
Use a two-dimensional array to visit each point in the oil field. Once @ is traversed, and @ has not been visited, it will be enqueued for BFS traversal, and all @ signs enqueued are set to have been visited. After the traversal is complete, sum+1.

to sum up:

  1. Since DFS is easier to write (about 70 lines of BFS code and 24 lines of DFS code), DFS is often used to find connected blocks
  2. There are generally three types of maze problems:
    1. Determine whether the point is out of bounds
    2. Determine whether the point is an obstacle
    3. Determine whether the point has been passed
  3. Use a double loop to find the adjacent 8 grids of the current grid, which is concise and efficient (of course, constant arrays can also be used)
  4. Whether you want to backtrack first, then determine, or determine first, then backtrack, you should choose flexibly according to the meaning of the question. Generally speaking, it is more efficient to backtrack first and then determine later.
  5. When I first wrote BFS, I made a lot of nesting. Although AC was dropped, it looked very ugly. Therefore, function call and function block are still very important.

DFS solution

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

char pic[Max][Max];
int m, n, idx[Max][Max];

void dfs(int r, int c, int id) {
    
    
	if(r<0 || r>=m || c<0 || c>=n) return;		//出界的格子
	if(idx[r][c] || pic[r][c]!='@') 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);  
}

int main() {
    
    
	while(cin>>m>>n && m) {
    
    
		for(int i = 0; i < m; i++) cin>>pic[i];//二维char数组的输入
		memset(idx, 0, sizeof(idx));
		int cnt = 0;
		for(int i = 0; i < m; i++) 
			for(int j = 0; j < n; j++) 
				if(!idx[i][j] && pic[i][j]=='@') dfs(i, j, ++cnt);
		cout << cnt << '\n';
	}
return 0; }

BFS solution

#include<iostream>
#include<cmath>
#include<cstring> 
using namespace std;

struct Queue{
    
    
	int x, y;	//横纵坐标
	int s;		//步数 
}; 

int Next[4][2] = {
    
    1,0, -1,0, 0,1, 0,-1};
int vis[110][110];
char Oil_field[110][110];

int n, m;
int head, tail;

void Input() {
    
    
	for(int i = 0; i < n; i++) cin>>Oil_field[i];
}

void BFS(int i, int j) {
    
    
	//初始化 
	Queue que[10010];
	head = tail = 1;		//队列初始化 ,入第一个坐标
	//插入入口坐标
	que[tail].x = i, que[tail].y=j;
	que[tail].s = 0;
	tail++;
	vis[i][j] = 1;
	
	
	while(head < tail) {
    
    
		//枚举八个方向,这里仔细体会 
		for(int dr=-1; dr<=1; dr++) 
		for(int dc=-1; dc<=1; dc++) 
			if(dc!=0 || dr!=0) {
    
    
				//计算下一个点的坐标
		 		int tx = que[head].x + dr;
				int ty = que[head].y + dc;
				//1、判断是否越界
				if(tx<0 || tx>=n || ty<0 || ty>=m) continue;
				//2 3 判断是否是障碍物或已经在路径中
				if(Oil_field[tx][ty]=='@' && vis[tx][ty]==0) {
    
    
					//标记为已走过 
					//注意宽搜每个点只入队一次,所以不要需要连book数
					vis[tx][ty] = 1;
					que[tail].x = tx;
					que[tail].y = ty;
					que[tail].s = que[head].s + 1;	//步数+1
					tail++; 
				} 
			}	
	head++; 
	}
}

int main() {
    
    
	ios::sync_with_stdio(false); 
	while(cin>>n>>m && n) {
    
    
		memset(vis, 0, sizeof(vis));		//全局变量初始化 
		
		Input();
		
		int sum = 0;
		for(int i = 0; i < n; i++) 
			for(int j = 0; j < m; j++) {
    
    
				if(Oil_field[i][j]=='@' && !vis[i][j]) {
    
    	 
					BFS(i,j);
					sum++; 
				}
			}
		cout << sum << endl;
	}		//while循环的括号 
	return 0;
} 

This world is that some people are always working day and night, while others find that the world has changed when they wake up. Come on, stranger!

Guess you like

Origin blog.csdn.net/weixin_43899069/article/details/108847403