关于算法笔记8.2BFS中例题“求给定矩阵中块的个数”的DFS实现

算法笔记8.2节给了这样一个例题:

给出一个m*n的矩阵,矩阵中的元素为0或1.称位置(x,y)与其上下左右四个位置是相邻的。如果矩阵中有若干个1是相邻的(不必两两相邻),那么称这些1构成了一个“块”。求给定的矩阵中“块”的个数。

0111001
0010000
0000100
0001110
1110100
1111000

例如上面的6*7的矩阵中,块的个数为4。

在算法笔记中给出的BFS解法如下:

/*------------BFS---------------*/

#include<cstdio>
#include<iostream>
#include<queue>
using namespace std;

const int maxn=100;

struct node{
	int x,y;
}Node;

int n,m;//矩阵大小
int matrix[maxn][maxn];//01矩阵
bool inq[maxn][maxn]={false};//记录位置(x,y)是否被记录过
int X[4]={0,0,1,-1};
int Y[4]={1,-1,0,0};

/*判断点(x,y)是否被访问过*/
bool judge(int x,int y){
	if(x>=n||x<0||y>=m||y<0)return false;
	if(matrix[x][y]==0||inq[x][y]==true)return false;
	return true;
}

void BFS(int x,int y){
	queue<node> Q;
	Node.x=x,Node.y=y;
	Q.push(Node);
	inq[x][y]=true;//记录该点已经被访问过
	while(!Q.empty()){
		node top=Q.front();//取出队首元素
		Q.pop();//队首元素出队
		for(int i=0;i<4;i++){
			int newX=top.x+X[i];
			int newY=top.y+Y[i];
			if(judge(newX,newY)){
				//如果点(newX,newY)没有被访问过,那么将该点入队并且标记为已经被访问过
				Node.x=newX,Node.y=newY;
				Q.push(Node);
				inq[newX][newY]=true; 
			}
		} 
	} 
}

int main(){
	scanf("%d%d",&n,&m);
	for(int i=0;i<n;i++){
		for(int j=0;j<m;j++){
			scanf("%d",&matrix[i][j]);
		}
	}
	int ans=0;//记录答案块数
	for(int x=0;x<n;x++){
		for(int y=0;y<m;y++){
			if(matrix[x][y]==1&&inq[x][y]!=1){
				//如果该点满足要求而且尚未被访问过,那么块数ans++并且执行BFS
				ans++;
				BFS(x,y); 
			}
		}
	} 
	printf("%d\n",ans);
	return 0;
}

然后根据这个解法,我改写了一个用DFS实现的算法:

/*---------DFS---------*/

bool end(int x,int y){
	for(int i=0;i<4;i++){
		if(matrix[x+X[i]][y+Y[i]]==1&&inq[x+X[i]][y+Y[i]]==false){
			return false;
		}
	}
	return true;
}


void DFS(int x,int y){
	inq[x][y]=true;
	if(end(x,y))return;
	for(int i=0;i<4;i++){
		if(judge(x+X[i],y+Y[i])){
			DFS(x+X[i],y+Y[i]);
		}
	}
}

用递归实现DFS,因为要有递归边界,我的想法是当正在访问的这个点的上下左右为1的点都被访问过的时候就是递归边界,所以我写了一个end函数,当正在访问的这个点的上下左右为1的点只要出现了有一个点没被访问过,就返回false,意味着没有到递归边界,应当继续执行DFS,否则end函数就返回true,意味着到达递归边界,return。不知道我这样的想法是对还是错,欢迎看到这篇博客的人能提一些建议。


其实通过这个例子,我更加充分地更深入地理解了DFS和BFS的思想,也加深了我对递归和分治的理解。


评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值