bfs解题

题目;

GeoSurvComp地质勘测公司负责检测地下油藏。GeoSurvComp一次处理一个大矩形区域的土地,并创建一个将土地分成许多正方形图的网格。然后,使用传感设备分别分析每个地块,以确定该地块是否包含油。含有油的地块称为矿穴。如果两个凹坑相邻,则它们是同一油藏的一部分。积油可能很大,可能包含许多凹穴。您的工作是确定网格中包含多少种不同的油藏。
输入值
输入包含一个或多个网格。每个网格均以包含m和n的行开始,网格中的行和列数由单个空格分隔。如果m = 0,则表示输入结束;否则,输入0。否则为1 <= m <= 100和1 <= n <=100。紧随其后的是m行,每行n个字符(不计算行尾字符)。每个字符对应一个地块,要么是代表无油的“ *”,要么是代表油囊的“ @”。

输出量
在水平,垂直或对角线上相邻。积油最多可容纳100个口袋。
样本输入
1 1
*
3 5
@@*
@
@@*
1 8
@@***@
5 5
****@
@@@
@**@
@@@
@
@@**@
0 0
样本输出
0
1
2
2

代码:

#include<stdio.h>
#include<string.h>

int f(int i,int j,int q);
char a[110][110];
int c[10][10]={{1,0},{1,1},{1,-1},{-1,0},{-1,-1},{-1,1},{0,1},{0,-1}}; 
int m,n; 

int main()
{
	int i,k,j,g=0,q,e,z=0;
	int b[110]={0};
	while((scanf("%d %d",&m,&n)),m!=0&&n!=0)
	{
		//scanf("%d",&z);//清空缓存; 
		
		memset(b,0,sizeof(b));//初始化;
		//memset(a,0,sizeof(a)); 
		
		for(i=0;i<m;i++)//输入  这里若用字符一个一个输入会吞掉回车导致错 
		{	
			//for(j=0;j<n;j++)
				scanf("%s",a[i]);
			getchar();		
		}
		/*
		for(i=0;i<m;i++)
		{
			for(j=0;j<n;j++)
				printf("%c",a[i][j]);
			printf("\n");
		}
		*/			
		k=0;
		for(i=0;i<m;i++)// 遍历 
			for(j=0;j<n;j++)
			{
				q=0;
				if(a[i][j]=='@')//判断 
				{
					q=f(i,j,q);// 递归计算每一片@的个数;
				//	printf("%d %d\n",i,j);
					//printf("%d ",q); 
					//b[q]++;//存储   这个可以把下面取代; 
					k++;
				}	
			}
		
		/*	
		for(i=0;i<k;i++)//排序 
			for(j=0;j<i;j++)//这里其实可以改成一个一百的数组里面都是0,例如5个油田有2个,就让数组地址为5的值加加变成2;这种方法很简单; 
			{
				if(b[i]<b[j])
				{
					e=b[j];
					b[j]=b[i];
					b[i]=e;
				}
			}
		*/	
		g=0;
		//b[k]=0;
		for(i=0;i<103;i++)//寻找不同的数,并计数; 
		{
			if(b[i]!=0)
				g++;
		}
	//	for(i=0;i<m;i++)
	//		printf("%s\n",a[i]);
	
		printf("%d\n",k); 
	}
	
	
}
int f(int i,int j,int q)//这里可以把下面简化; 
{
	int k;
	
	q++;
	a[i][j]='*';
	
	for(k=0;k<8;k++)
	{
		if((i+c[k][0])>=0&&(i+c[k][0])<=m&&(j+c[k][1])>=0&&(j+c[k][1])<=n&& a[i+ c[k][0] ][j+ c[k][1] ]=='@')
			q=f(i+c[k][0],j+c[k][1],q);
		
	}
	return q;	
}
/*
int f(int i,int j,int q)//八个方向 
{
	//printf("%d %d ",i,j);
	q++;
	a[i][j]='*';
	
	if(a[i+1][j]=='@'&&i+1<m)
		q=f(i+1,j,q);
		
	if(a[i+1][j+1]=='@'&&i+1<m&&j+1<n)
		q=f(i+1,j+1,q);
		
	if(a[i+1][j-1]=='@'&&i+1<m&&j-1>=0)
		q=f(i+1,j-1,q);
		
	if(a[i-1][j]=='@'&&i-1>=0)
		q=f(i-1,j,q);
		
	if(a[i-1][j+1]=='@'&&i-1>=0&&j+1<n)
		q=f(i-1,j+1,q);
		
	if(a[i-1][j-1]=='@'&&i-1>=0&&j-1>=0)
		q=f(i-1,j-1,q);
		
	if(a[i][j-1]=='@'&&j-1>=0)
		q=f(i,j-1,q);
		
	if(a[i][j+1]=='@'&&j+1<n)
		q=f(i,j+1,q);
	
	return q;
 } 
 10 10
*@@*@*@@*@
*@@*@*@@*@
**********
*@@*@*****
*@@*@****@
**********
*@@*@*****
*@@*@*@@*@
******@@*@
******@@*@
 1 1
*
3 5
*@*@*
**@**
*@*@*
1 8
@@****@*
5 5 
****@
*@@*@
*@**@
@@@*@
@@**@
0 0
 
 
 
 */
 //memset()  可以用于初始化数组和字符数组; 

总结:

总体来看,这个题也不是很坑,就是我自己对知识点掌握不牢固。

错误总结:

1. 首先一上去我就把题意分析错误了,人家问的是有多少中不同的油藏。我理解的是,数不一样才算是不同的油藏,可人家的意思是***只要不连在一起就是不同的油藏***!

知识总结:

1. 初始化问题memset(b,0,sizeof(b));这个可以直接对数组和字符数组进行初始化,很快,很方便;
2. 二维字符数组的输入:其实有两种,
第一种:直接字符串输入;

for(i=0;i<m;i++)
		{	
			
				scanf("%s",a[i]);
			getchar();		
		}

这种输入特别方便,不易出错,(出错是指输入\n时各种报错,特指那类,好几行的输入,前面一行输入完按回车,这个回车如果是单字符输入时很有可能会被输入下个数组,而出错!);

第二种:单字符输入

for(i=0;i<m;i++)
{
	for(j=0;j<n;j++)
		{	
			
				scanf("%c",&a[i][j]);
		}
	getchar();	
}			

这种输入报错运行错误时,如果前面输入的是数字可以加一行,scanf(“%d”);就过了 如果是字符加getchar;最好选用第一种方法;

3. 对自己习惯代码的优化
第一种
对数字进行标记时,例如,5 5 6 7 7 2 2 2 8 问其中重复数字多少个,那个重复最多,那个最大,这类问题,用地址查找法相当的牛,遇到5,让a[5]++;遇到6;让a[6]++;非常好理解,方便!

第二种:用递归深度搜索时,我以前是这样写

int f(int i,int j,int q)//八个方向 
{
	//printf("%d %d ",i,j);
	q++;
	a[i][j]='*';
	
	if(a[i+1][j]=='@'&&i+1<m)
		q=f(i+1,j,q);
		
	if(a[i+1][j+1]=='@'&&i+1<m&&j+1<n)
		q=f(i+1,j+1,q);
		
	if(a[i+1][j-1]=='@'&&i+1<m&&j-1>=0)
		q=f(i+1,j-1,q);
		
	if(a[i-1][j]=='@'&&i-1>=0)
		q=f(i-1,j,q);
		
	if(a[i-1][j+1]=='@'&&i-1>=0&&j+1<n)
		q=f(i-1,j+1,q);
		
	if(a[i-1][j-1]=='@'&&i-1>=0&&j-1>=0)
		q=f(i-1,j-1,q);
		
	if(a[i][j-1]=='@'&&j-1>=0)
		q=f(i,j-1,q);
		
	if(a[i][j+1]=='@'&&j+1<n)
		q=f(i,j+1,q);
	
	return q;
 } 

特别的麻烦,重复的代码很多,还可以这样写,

int f(int i,int j,int q)//这里可以把下面简化; 
{
	int k;
	
	q++;
	a[i][j]='*';
	
	for(k=0;k<8;k++)
	{
		if((i+c[k][0])>=0&&(i+c[k][0])<=m&&(j+c[k][1])>=0&&(j+c[k][1])<=n&& a[i+ c[k][0] ][j+ c[k][1] ]=='@')
			q=f(i+c[k][0],j+c[k][1],q);
		
	}
	return q;	
}

加一个全局数组,int c[10][10]={{1,0},{1,1},{1,-1},{-1,0},{-1,-1},{-1,1},{0,1},{0,-1}};用于修改方向,极为方便。

最后就是一些琐碎的点点了:while(scanf("%d",&a)!=EOF,&&n!=0)这里的,可以替换成“&&”;

兄弟们,我知道我笨,但这个人人皆知的问题就不用了说了!&_&!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值