题目;
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)这里的,可以替换成“&&”;
兄弟们,我知道我笨,但这个人人皆知的问题就不用了说了!&_&!