您的位置:首页 > 编程语言 > C语言/C++

【DFS&BFS】HDU1241-Oil Deposits

2016-07-30 09:59 435 查看
【这里不用看】这是一道神奇的题,它之所以神奇不是因为它有多实用,也不是因为它有多难,而是因为它可以用两种方法解出来:一种是深搜(DFS),另一种是广搜(BFS)。所以学长连着两天把这道题叫我们用这两种方法练习,结果第二天还真的有个boy上去就用了第一天的方法把代码bia上去然后显示两分钟就完成了,感觉很厉害的样子呢~(不是我不是我不是我)

【题目】

Oil Deposits

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)

Problem Description

The GeoSurvComp geologic survey company is responsible for detecting underground oil deposits. GeoSurvComp works with one large rectangular region of land at a time, and creates a grid that divides 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.

 

[align=left]Input[/align]
The input file contains one 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.

 

[align=left]Output[/align]
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.

 

[align=left]Sample Input[/align]

1 1
*
3 5
*@*@*
**@**
*@*@*
1 8
@@****@*
5 5
****@
*@@*@
*@**@
@@@*@
@@**@
0 0

 

[align=left]Sample Output[/align]

0
1
2
2

 
[align=left]Source[/align]
Mid-Central USA 1997 

【题意】

自从进协会我已经很久没看到中文题了TAT,渣渣英语谁来救救我!

说是第一行输入行列数(输入行数为0时结束),下面紧跟着的几行几列由*和@组成,要求输出一个数字,表示有几组连着的@。

注意这里面相邻斜着的@也算是连着的!

【思路】

先说深搜吧,深搜的原理就是顺着一条路直接找到头再拐回来找其他的路,对于这道题来讲,它拐回来时是不需要再把标记重置的,踩过一遍之后草就死了,所以当我们找到一个@并开始找跟它连在一起的@以后,直接把连在一起的@标记已访问,回去时访问不重置,那么跟这个@连着的这一片@就都不用再检查了,下次再进入函数,就是从另外的没遍历过的@开始找。这样的话,我们从main函数里传递给dfs函数几个@的坐标,就有几个连在一起的@群了。

至于广搜,原理跟深搜是一样的,但是广搜用了15ms,深搜用了46ms,更省了点时间。广搜需要用到队列,而坐标是二维的,这就要求推入队列时要把储存着坐标位置信息的结构推进去,要建立结构体,推入队列的都是将要被检查的元素,当队列非空时取出元素依次检查。

【代码】

DFS:

<pre name="code" class="cpp">#include<cstdio>
#include<string.h>
#define N 101
using namespace std;

int dir[8][2]={{1,0},{-1,0},{0,1},{0,-1},{1,1},{-1,1},{1,-1},{-1,-1}};//由于斜着也算连着,所以设置8个方向
int mark

,b

,m,n,ans;//mark[][]用来检查该位置元素是否被遍历,是为1,否为0;至于b[][]额……只是一个迷の数组;
char a

;

int dfs(int x,int y);

int main()
{
while(scanf("%d%d",&m,&n)&&m)
{
ans=0;
memset(b,0,sizeof(b));
memset(mark,0,sizeof(mark));//输入数据可能有多组,所以每次计算之前都要重置mark每一项都为0,表示都还没有遍历,ans也要重置为0;
for(int i=0;i<m;i++)//输入地图数据
{
for(int j=0;j<n;j++)
{
char aa;
o:scanf("%c",&aa);
if(aa=='\n'||aa=='\0')
goto o;
else if(aa=='@')
b[i][j]=1;
a[i][j]=aa;
}
}
for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++)
{
if(b[i][j]==1&&mark[i][j]==0)//如果@没有遍历,就让答案ans+1,
{
ans++;
dfs(i,j);//实际上dfs函数在这里的作用就是把跟被检查的@连在一起的@全部标记为已遍历。
}
}
}
printf("%d\n",ans);
}
}

int dfs(int x,int y)
{
mark[x][y]=1;//标记此坐标为已遍历
for(int i=0;i<8;i++)
{
int nx=x+dir[i][0];//nx、ny为以原始x,y值为基础向8个方向走一步时新坐标的数值
int ny=y+dir[i][1];
if(nx>=0&&ny>=0&&nx<m&&ny<n&&!mark[nx][ny]&&a[nx][ny]!='*')//检查新坐标是否越界、是否已被遍历,是不是@符号
{
dfs(nx,ny);//符合条件的话标记此坐标
}
}
}




BFS:

<pre name="code" class="cpp">#include<cstdio>
#include<string.h>
#include<queue>//BFS需要队列来辅助
using namespace std;

int m,n,ans,vis[101][101],dir[8][2]={1,0,-1,0,0,1,0,-1,1,-1,1,1,-1,-1,-1,1};
char a[101][101];
struct inf{        int x,y;    }xy;//结构,用来做压缩包把坐标合二为一
queue <inf> q;

void bfs(void);

int main()
{
while(~scanf("%d%d",&m,&n)&&m)
{
while(!q.empty())
q.pop();//重置队列
memset(vis,0,sizeof(vis));//重置访问标记
ans=0;
getchar();
for(int i=0;i<m;i++)//输入数据
{
scanf("%s",&a[i]);
}
for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++)
{
if(a[i][j]=='@'&&vis[i][j]==0)//此处原理同DFS
{
xy.x=i;xy.y=j;//压缩坐标
q.push(xy);//入队
bfs();//进入bfs进行标记
ans++;
}
}
}
printf("%d\n",ans);
}
}

void bfs(void)
{
while(!q.empty())
{
xy=q.front();//出队,开始标记此元素并检测其周围元素是否有@符号
q.pop();//这个……别忘了就好
int X=xy.x;
int Y=xy.y;
vis[X][Y]=1;//标记
for(int i=0;i<8;i++)
{
int nx=X+dir[i][0];
int ny=Y+dir[i][1];
if(a[nx][ny]=='@'&&nx>=0&&nx<m&&ny>=0&&ny<n&&vis[nx][ny]==0)
{
vis[nx][ny]=1;
xy.x=nx;xy.y=ny;
q.push(xy);//符合条件的将此节点作为起点先推入队,放到后面来检查此节点周围是不是还存在相邻@符
}
}
}
}




唯一两种方法都一次过掉的题,虽然不难但是总要写个博客纪念一下~~~!

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c语言 函数 递归 bfs DFS