面积(BFS广搜算法)

一 问题描述

编程计算由 " 1 " 围成的下列图形的面积。面积的计算方法是统计" 1 "所围成的闭合曲线中水平线和垂直线交点的数目。如下图所示,在10*10的二维数组中,有" 1 "围住了15个点,因此面积为15。如图所示

                                                                                                   

以下提供了几个测试的案例:

二 解题思路

这道题可以用BFS广度优先搜索算法来解题,通过BFS找到所有不被“ 1 ”包围的“ 0 ”,将其置为“ 1 ”最终去判断二维数组中还剩下多少个“ 0 ”就可以算出面积,重点可以关注图3,既然要算“ 1 ”围起来的面积,那么可以从图形的四边出发,因为如果不考虑四边的话,假设以图3为例,假设从非边缘的“ 0 ”出发,那么通过广度搜索算法,能够被遍历到的只是蓝色圈起来的那一部分。这样子,我们之后算“ 0 ”的个数,就会大于11,因为左上角的“ 0 ”也被算进去了,实际上,它是不应该被算进去的因为它们并没有被" 1 "完全包围。这就是为什么要考虑四边的情况,因为从4个边出发,最终总是会把所有不被“ 1 ”包围的所有“ 0 ”遍历到

    

三 核心代码实现 

BFS我们可以利用队列这种数据结构来实现,但是在程序之中我们有几个点需要注意

1. 数据的输入问题

          题目并没有告诉我们图形的行和列的值,因此,需要考虑用户输入的数据要如何进行存储?,我们可以利用文件的结尾来判断用户输入是否结束,把用户输入的行数和列数用两个变量记录起来。具体代码实现如下:

char c;
int m,n;   //m代表行,n代表列
int i=1,j=1,sum=0;   //sum代表总共输入的字符个数
c = getchar();
while(c!=EOF)
{
		if(c!=' ')          //如果输入的不是空格
		{ 
			if(c!='\n')     //如果输入的不是空格,也不是换行,那么一定是0或者1,需要进行记录
			{
				a[i][j]=c-'0';   //数组从(1,1)开始
				sum = sum+1;     //记录0和1的个数
				j=j+1;           //列数加1
			}
			else            //到达行尾 
			{
				n=j-1;      //n代表列,j需要-1,因为上一次循环的时候j已经++了,需要减回来 
				i=i+1;      //i代表行数,此时到达下一行,i需要+1
				j=1;        //从新的一行开始输入,j重新置为1
			}
		}

		c=getchar(); 
} 
m=sum/n;  //循环结束后,输入完毕,知道了列数,知道了总的0或1的个数,就可以算出行数,m代表行数
 

 

2. 当前点怎么扩展到周围的4个点?

          因为是BFS,所以需要从周围一层一层进行扩展,那么当前点怎么扩展到四周呢?

   

我们可以用两个数组来进行点的扩展,在原来的基础上进行四个方向的拓展,假设当前坐标在(x,y) ,以下两个数组代表上下左右四个方向 :       

int dx[4]={-1,1,0,0};       int dy[4]={0,0,-1,1};     

(x,y)的上面那个单元格坐标为:(x+dx[0],y+dy[0])   

(x,y)的下面那个单元格坐标为:(x+dx[1],y+dy[1])   

(x,y)的左边那个单元格坐标为:(x+dx[2],y+dy[2]) 

(x,y)的右边那个单元格坐标为:(x+dx[3],y+dy[3])     

3. 每一个坐标点怎么表示?

可以用一个结构体struct对坐标点(x,y)进行封装

struct Point{
	int x;
	int y;
};

4. 如何扫描不被1包围的0,并且将其置1?

可以利用队列这个数据结构来写代码,从上下左右四条边出发扫描,我们以下图为例,演示一下

第一步:扫面最上面的边(其它三条边的广搜步骤和第一条边一样),第一个坐标为(1,1),将其入队

第二步:判断队列是否为空,如果不为空,将队头元素弹出,并且判断这个坐标的值是否为0,如果是,将它的值置1,代表这个坐标已经访问过了,并且扫描这个被弹出的元素的上下左右四个方向的坐标,如果它周围的四个坐标还没有被访问过的话(值为0),就将其入队,请注意,要特别注意画下划线的那句话,代码的顺序如果写错,那可是天差地别的!!!,此时,可以看出,我们要将如下两个点入队

第三步:重复第二步,将队头元素弹出,此时就是弹出(2,1),并判断它是不是为0,如果是的话,将坐标对应的值置为1,然后继续扫描这个坐标上下左右四个方向的坐标.......以此类推。

注意:一定要去判断当前弹出队列的这个点是不是已经被访问过了,因为有的点可能会被入队列多次,如果不去判断这个点是否被访问过,会出现同一个点的四周被扫描两次,出现混乱。

四 完整代码实现  

 整个程序的完整代码如下:

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

struct Point{
	int x;
	int y;
};

int m,n,s,sum;
int a[100][100];

void prt(int m,int n)
{
	int i,j;
	for(i=1;i<=m;i++)
	{
		for(j=1;j<=n;j++)
		{
			cout<<left<<setw(2)<<a[i][j];
		}
		cout<<endl;
	}
}
queue<struct Point> q;
void epd(int i,int j)
{
	int k,ni,nj;
	//代表上下左右四个方向 
	int dx[4]={-1,1,0,0};
	int dy[4]={0,0,-1,1};
	struct Point p;
	p.x=i;p.y=j;
	q.push(p);   //入队
	while(!q.empty())
	{
		p=q.front(); q.pop();
		i=p.x; j=p.y;
		if(a[i][j]==0)  //这个不能可有可无,访问的是一个没有访问过的点,而且可达,访问过就不用入队了   ,如有的点会入队多次,比如2,2 ,如果有if,我们还会再判断,这个点是不是0,此时它已经不是了 
		{
				a[i][j]=1;
				for(k=0;k<=3;k++)  //探索四个方向
				{
					ni=i+dx[k];
					nj=j+dy[k];   //新坐标
					if(1<=ni&&ni<=m&&1<=nj&&nj<=n&&a[ni][nj]==0)
					{   
						//cout<<ni<<" "<<nj<<endl; 
						p.x=ni;p.y=nj;
						q.push(p);	
					}
				}
		} 
	} 
}

int main()
{
	int i,j,ans=0;
	char c;
	i=1;j=1;sum=0;
	c=getchar();
	while(c!=EOF)
	{
		if(c!=' ')
		{
			if(c!='\n')
			{
				a[i][j]=c-'0';
				sum = sum+1;
				j=j+1;
			}
			else  //到达行尾 
			{
				n=j-1; //n代表列 
				i=i+1;
				j=1;
			//	cout<<"haha"<<endl;
			}
		}

		c=getchar(); 
	} 
	m=sum/n;
	//prt(m,n);
	//探索四条边
	for(j=1;j<=n;j++)
	{
		epd(1,j);
		epd(m,j);
	 } 
	 for(i=1;i<=m;i++)
	 {
	 	epd(i,1);
	 	epd(i,n); 
	 }
	// prt(m,n);  if不能可有可无 
	for(i=1;i<=m;i++)
	for(j=1;j<=n;j++)
	if(a[i][j]==0)  ans++;
	cout<<ans;
	return 0; 
} 

 

  • 10
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
BFS广度优先搜索算法(Breadth-First Search)是一种图的算法,也是最简便的图算法之一。它的目的是系统地展开并检查图中的所有节点,以找寻结果。这个算法不考虑结果的可能位置,而是彻底地索整张图,直到找到结果为止。广度优先搜索算法通常用于找出两个节点之间的最短路径。它可以帮助我们解决类似于寻找最短路径的问题。 BFS算法的基本思想是从起始节点开始,逐层地向外扩展,先访问离起始节点最近的节点,再逐渐向外层节点扩展,直到达到目标节点。它使用队列来存储待访问的节点,先进先出(FIFO)的特点保证了广度优先。通过不断地将节点加入队列并访问,直到队列为空,我们可以遍历整张图并找到最短路径。 BFS广度优先搜索算法的运行时间为O(V+E),其中V为顶点数,E为边数。它可以指出是否存在从起始节点到目标节点的路径,并且可以找到最短路径。当面临需要寻找最短路径的问题时,我们可以使用图来建立模型,并使用广度优先搜索算法解决问题。 参考资料: https://www.cnblogs.com/tianqizhi/p/9914539.html 文中引用的参考资料<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [代码 基于BFS广度优先搜索算法代码](https://download.csdn.net/download/s13166803785/85545057)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [广度优先搜索算法BFS)详解](https://blog.csdn.net/lemonxiaoxiao/article/details/105730735)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值