浅析-啊哈算法-宝岛探险
欢迎大家批评指正
//啊哈算法114~116页代码
/*使用深度优先 求地图上的独立小岛数*/
#include <stdio.h>
int a[51][51];
int book[51][51],n,m,sum;
void dfs(int x,int y,int color)
{
int k,tx,ty;
//定义一个方向数组 依次向右、向下、向左、向上(即顺时针)
int next[4][2]={{0,1},
{1,0},
{0,-1},
{-1,0}};
a[x][y]=color;//对a[x][y]这个格子染色
//四个方向依次遍历
for(k=0;k<4;k++)
{
tx=x+next[k][0];//要检查的下一坐标
ty=y+next[k][1];
//判断是否越界
if(tx<1||tx>n||ty<1||ty>m)
continue;
//判断是否为陆地 及 是否被标记
if(a[tx][ty]>0 && book[tx][ty]==0)
{
sum++;
book[tx][ty]==1; //标记该点已走过
dfs(tx,ty,color); //对该点着色 继续执行dfs()尝试下一点
}
}
return;
}
int main()
{
int i,j,num=0;
scanf("%d %d %d",&n,&m); //输入行列数 n m
//读入地图数据
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
scanf("%d",&a[i][j]);
//对每个大于0的点尝试进行dfs染色
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
if(a[i][j]>0){
num--;
book[i][j] = 1;
dfs(i,j,num);
}
}
}
//输出染色后的地图
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
printf("%3d",a[i][j]);//3是C语言中的场宽
}
printf("\n");
}
//输出小岛的个数
printf("有%d个小岛\n",-num;/
getchar();getchar();
return 0;
}
-
有关主函数中dfs的使用
- 假设从(1,1)出发,即i=1,j=1
- 已知a[1][1]>0,所以num–此时为-1,book[1][1]标记为1,执行dfs(1,1,-1)
-
观察dfs(),第一个大循环:k=0时
1.
( 向右走) 下一步坐标(1,2),因为if判断条件a[1][2]>0&&book[1][2]==0成立,所以sum=1,book[1][2]=1(被标记),接下来对(1,2)的下一个点进行尝试,
2.
即(1,3),同理,因为if判断条件a[1][3]>0&&book[1][3]==0 成立,所以sum=2,book[1][3]=1(被标记),接下来对(1,3)的下一个点进行尝试,
3.
即(1,4),此时因为if判断条件a[1][3]>0&&book[1][3]==0 不成立,所以 回溯(因为此时k=0的dfs(1,3,-1)执行完,要继续k的循环) 即对刚刚经过的点进行其他方向(k++)的搜索,一直回溯到(1,1),对(1,1)点进入下一方向搜索:k=1(向下)
4.
与上述步骤相同,一直判断到if条件不成立为止,之后再回溯 换方向
5.
对(1,1)深度搜索完成后,与其能连接到的点都被染色成 -1
6.
接下来主函数中循环进行,依然i=1,对j遍历,由上分析知(1,2),(1,3)已被标记,又因为j=4~8时,a[1][j]==0,所以直接到j=9,再进行以上循环,此时num–为-2
7.
之后的就好理解了,把i遍历完即可。
书上说这是一个 求图中独立子图的个数 的问题
此算法为Floodfill漫水填充法,也称种子填充法