Lake Counting 深搜与广搜(二)

昨天给了道广搜的题目,那么今天在总结深搜和广搜之前先来一道深搜题目。
POJ Lake Counting

题目:

Due to recent rains, water has pooled in various places in Farmer John’s field, which is represented by a
rectangle of N x M (1 <= N <= 100; 1 <= M <= 100) squares. Each square contains either water (‘W’) or dry land (‘.’). Farmer John would like to figure out how many ponds have formed in his field. A pond is a connected set of squares with water in them, where a square is considered adjacent to all eight of its neighbors.
Given a diagram of Farmer John’s field, determine how many ponds he has.
Input
Line 1: Two space-separated integers: N and M
Lines 2…N+1: M characters per line representing one row of Farmer John’s field. Each character is either ‘W’ or ‘.’. The characters do not have spaces between them.
Output
Line 1: The number of ponds in Farmer John’s field.
Sample Input
10 12
W………WW.
.WWW……WWW
….WW…WW.
………WW.
………W…
…W……W…
.W.W……WW.
W.W.W……W.
.W.W……W.
…W…….W. 2
Sample Output
3
Hint
OUTPUT DETAILS:
There are three ponds: one in the upper left, one in the lower left,and one along the right side.

大意就是:有一个N x M的园子,雨后积起了水。八连通的积水被认为是连接在一起的。请求出园子中共有多少块水洼?(W代表积水,‘.’表示没有积水,八连通指的是一个九宫格内相对于中央一格的周围八格)
N,M<=100.

(给出AC代码),算了不偷懒了先分析一下。
本题可以从任意一个W开始,把与他连接的W变成 ‘ . ’,这样经过一次dfs就会把与这个W相连的所有W都变成了 ’ . ’ 所以一直到图中不再有W为止,一共进行的dfs次数就是水洼数。
八连通对应了8种状态转移。
先给出代码,稍后继续分析深搜和广搜:

#include <stdio.h>
#define sf scanf
int N,M;
char ma1p[105][105];
void dfs(int x,int y)
{
    ma1p[x][y] = '.';
    for(int i = -1;i <= 1;i++)
        for(int j = -1; j <= 1;j++)
        {
            int xi = x + i;
            int yj = y + j;
            if(xi >= 0 && xi < N && yj >= 0 && yj < M && ma1p[xi][yj] == 'W')
                dfs(xi,yj);
        }
}
int main()
{
    sf("%d%d",&N,&M);
    int ans = 0;
    for(int i = 0;i < N;i++)
            sf("%s",ma1p[i]);
    for(int i = 0;i < N;i++)
        for(int j = 0;j < M;j++)
            if(ma1p[i][j] == 'W')
            {
                dfs(i,j);
                ans++;
            }
    printf("%d\n",ans);
}

深搜与广搜

深度优先搜索就是从一个状态开始,遍历所有可能到达的状态。由此可以对所有的状态进行操作,或者列举出所有的状态。广度优先搜索和深度优先搜索类似,可以从某个状态出发搜索所有可以到达的状态。
两者的区别是搜索的顺序不同,广搜总是先搜索距离初始状态最近的状态,而深搜是沿着某一路径一直搜索直到碰壁。深搜隐式的利用栈来计算,广搜则利用队列。
一般来说,广搜常用于找单一的最短路线,或者是规模小的路径搜索,它的特点是"搜到就是最优解", 而深搜用于找多个解或者是步数已知的情况,但找到解时不一定是最优解。在前面两个题目中可以看出深搜的空间效率比较高同时递归的写法使代码很简便,而广搜则是牺牲了空间换取时间。
一句话总结:
搜索树的形态,深搜层数良多,广搜则是很宽。深搜合适找出所有方案,广搜则用来找出最佳方案。

深搜的注意事项:
深搜的特性决定了他需要高效的剪枝,有时早已明确地知道从当前状态无论如何转移都不会存在解,这种情况下不再搜索直接跳过的方法叫做剪枝。
此外,还有采用与广搜类似的状态转移顺序,并且注重节约内存占用的迭代加深深搜IDDFS。这是一种在最开始将深搜的递归次数限制在一次,在找到解之前不断增加递归深度的方法。
要不,明天再说?

其实深搜和广搜的应用到这里差不多就结束了,明天再稍微整理一下IDDFS和一种深搜题型 “特殊状态的枚举”。

猜你喜欢

转载自blog.csdn.net/qm230825/article/details/86499492