Live2D

【Flood Fill】将相邻的点联合成一个块的算法(DFS)


对矩阵依据某种规则进行分块,通常采用DFS进行求解;
相似问题有迷宫问题,迷宫问题可依据剪枝条件进行广度优先搜索,减小复杂度;eg:胜利大逃亡/剪枝算法

1. Oil Deposit

题目:

The GeoSurvComp geologic survey company is responsible for detecting underground oil deposits. GeoSurvCompworkswithonelargerectangularregionoflandatatime,andcreatesagridthatdivides 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 containsone 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

题意:大致意思是说,现在有长方形的地,‘*’代表普通土地,‘@’代表油田,如果‘@’的相邻(上下左右以及对角线八个方向)的也为油田,则认为他们是联通的。联通的油田可以称之为一块油田(一块油田内的“@”,直接或间接联通)。输入m、n表示地的长宽,紧接着输入“油田地图”,根据油田地图判断油田有几块并输出油田块的数量。

分析:首先想到遍历,当遇到一个油田元素A时,遍历它周围的八个元素寻找相邻油田。而相邻的油田的周围仍需继续遍历,由此可想到深度优先遍历DFS,当以A开始的深度遍历结束后,即成功分出了一块油田,油田数量加一;后续当再遍历到此块油田时可直接跳过,因为已经分出,所以可以加一个mark标记数组。

代码:

#include<bits/stdc++.h>
using namespace std;
#define MAX 101     
//最大长宽
 
int state[MAX][MAX];         //存储油田地图 
int mark[MAX][MAX];          //标记油田是否已经遍历过了,全局变量默认初始化为0 

int go[8][2]={               //分别朝八个方向移动的数组 
	0,-1,           
	0,1,
	-1,0,
	1,0,                     //上下左右
	-1,-1,
	-1,1,
	1,-1,
	1,1                      //四个角 
};


void DFS(int x,int y,int col,int row)
{
	for(int i=0;i<8;i++)            //八个方向遍历 
	{ 
		int tx=x+go[i][0];
		int ty=y+go[i][1];
		if(mark[tx][ty])   
			continue;      
		if(tx<1||tx>col||ty<1||ty>row)     
			continue;
		if(state[tx][ty])     //也为油田 
		{
			mark[tx][ty]=1;
			DFS(tx,ty,col,row);       //深度优先 
		}
	} 
}

int main() 
{
	int col,row;  			//行,列 
	char tch;
	
	freopen("data.txt","r",stdin);
	while(1){
		int sum=0;				//油田的数量 
	
		cin>>col>>row;
		if(col==0||row==0)
			break;
	
		for(int i=1;i<=col;i++)    //决定直接采用坐标标记,方便
		{
			for(int j=1;j<=row;j++)
			{
				cin>>tch;
				if(tch=='@')
					state[i][j]=1;     //表示这一格为油田 
				else
					state[i][j]=0;     //表示这一格是普通土地 
					
				mark[i][j]=0;           //初始化一下 
			 } 
		} 
	
		for(int i=1;i<=col;i++) 
		{
			for(int j=1;j<=row;j++)
			{
				if(mark[i][j])  continue;           //标记过的不在遍历 
				if(state[i][j])                     //当为油田时
				{
					mark[i][j]=1;
					DFS(i,j,col,row) ;                      //遍历其周围
					sum++;                          //即使周围不再有油田,这一格也可构成一个油田块,所以加一	 
				} 
			}
		}
		cout<<sum<<endl;
	}

	return 0; 
}

这种分块的则使用DFS将一个个块分好,配合mark数组即可,如果是走迷宫(有时间限制,例如求最短时间,即需要求出最优方案,可以使用BFS,每走一步,标记,根据一些条件剪枝,删去一些不必要遍历的点。因为BFS在每一步都可以求出当前的最优情况。

posted @ 2020-03-03 17:20  WSquareJ  阅读(192)  评论(0编辑  收藏  举报