算法题-Oil Deposits HDU - 1241
题目描述:
GeoSurvComp地质调查公司负责探测地下油层。GeoSurvComp每次使用一个大的矩形区域的土地,并创建一个网格,将土地划分为许多正方形的小块。然后,它分别分析每个地块,使用传感设备来确定地块是否含有石油。含有石油的情节叫做口袋。如果两个储层相邻,那么它们就是同一油藏的一部分。石油储藏量可能很大,可能包含许多储层。您的工作是确定网格中包含多少不同的石油储量。
输入描述:
输入文件包含一个或多个网格。每个网格以包含m和n的行开始,m和n是网格中的行数和列数,用一个空格分隔。如果m = 0,表示输入结束;否则1 <= m <= 100和1 <= n <= 100。接下来是m行,每行n个字符(不包括行结束字符)。每个角色对应一个情节,“*”表示没有油,“@”表示油袋。
输出描述:
对于每个网格,输出不同的石油储量的数量。如果两个不同的储层在水平、垂直或对角线上相邻,那么它们就是同一油藏的一部分。一个石油矿床不会包含超过100个口袋。
输入样例 :
输出样例:
0
1
2
2
大致思路:
对于每一组测试样例:
在主函数中,先将油田的图存入到一个二维数组中,然后注意遍历这个二维数组,用一个变量来计数。当找到符合要求的坐标(该坐标位置对应的字符为‘@’,并且该坐标位置可以被访问)时,计数变量加一,并将该坐标位置设置成不可被访问,再将该坐标传到dfs函数中,直到遍历完整个数组(整幅图)。
在dfs函数中,从主函数中获得的坐标位置出发,向八个方向寻找,如果找到了‘@’,将该位置设置成不可被访问,再此调用dfs(递归思想),直到找不到为止,然后返回到主函数,继续进行二维数组的遍历。
代码解释:
char path[105][105];
bool bl[105][105];
int dx[8]={1,1,0,-1,-1,-1,0,1};
int dy[8]={0,1,1,1,0,-1,-1,-1};
此处定义path数组用来存储坐标(也就是图),bl数组用来标记某点坐标位置是否可以访问。(false为可以,true为不可以),而dx和dy数组用来进行坐标位置移动。
void dfs(int a,int b)
{
for(int i=0;i<8;i++)
{
int x=a+dx[i];
int y=b+dy[i];
if(path[x][y]=='@'&&bl[x][y]==false&&x>=0&&x<m&&y>=0&&y<n)
{
bl[x][y]=true;
dfs(x,y);
}
}
}
此处dfs函数用于将一个‘@’和与它连成一块的‘@’坐标位置设置为不可被访问,但是在搜索坐标位置时不能超出这个图。
int sum=0;
cin>>m>>n;
while(m!=0||n!=0)
{
memset(bl,false,sizeof(bl));
sum=0;
for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++)
{
cin>>path[i][j];
}
}
for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++)
{
if(path[i][j]=='@'&&bl[i][j]==false)
{
sum++;
bl[i][j]=true;
dfs(i,j);
}
}
}
cout<<sum<<endl;
cin>>m>>n;
}
本题输入为多组数据,输入0 0结束,所以用while控制输入,在进行每一组测试样例时,切记将bl数组初始化,并且将计数变量(sum)清零。在主函数中包括了读图操作还有遍历操作。
AC代码:
#include <iostream>
#include <cstring>
using namespace std;
char path[105][105];
bool bl[105][105];
int dx[8]={1,1,0,-1,-1,-1,0,1};
int dy[8]={0,1,1,1,0,-1,-1,-1};
int m,n;
void dfs(int a,int b)
{
for(int i=0;i<8;i++)
{
int x=a+dx[i];
int y=b+dy[i];
if(path[x][y]=='@'&&bl[x][y]==false&&x>=0&&x<m&&y>=0&&y<n)
{
bl[x][y]=true;
dfs(x,y);
}
}
}
int main()
{
int sum=0;
cin>>m>>n;
while(m!=0||n!=0)
{
memset(bl,false,sizeof(bl));
sum=0;
for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++)
{
cin>>path[i][j];
}
}
for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++)
{
if(path[i][j]=='@'&&bl[i][j]==false)
{
sum++;
bl[i][j]=true;
dfs(i,j);
}
}
}
cout<<sum<<endl;
cin>>m>>n;
}
}
本题总结:
本题采取的核心算法是搜索,上述代码用的是DFS,本题核心在于想清楚DFS的用途。本题的DFS用来将一个‘@’坐标位置和与它连成一块的‘@’坐标位置设置为不可被访问,这样一来在遍历二维数组时,不会将一块中的‘@’重复计算,从而达到目的。