搜索基础代码。

     说到搜索。都说泪啊。当初学长拉搜索题给我们做,一拉就是19道。当初对搜索是什么鸟蛋都不知道。大概一个星期,也才A了几道题。还有些都是从网上抄的。之后自己又慢慢琢磨了一个晚上。就大概懂了是怎么构成的了,下面来和大家谈一谈搜索。

搜索算法实际上是根据初始条件和扩展规则构造一棵“解答树”并寻找符合目标状态的节点的过程。所有的搜索算法从最终的算法实现上来看,都可以划分成两个部分——控制结构(扩展节点的方式)和产生系统(扩展节点),而所有的算法优化和改进主要都是通过修改其控制结构来完成的。其实,在这样的思考过程中,我们已经不知不觉地将一个具体的问题抽象成了一个图论模型——树,即搜索算法的使用第一步在于搜索树的建立。

由图一可以知道,这样形成的一棵树叫搜索树。初始状态对应着根结点,目标状态对应着目标结点。排在前的结点叫父结点,其后的结点叫子结点,同一层中的结点是兄弟结点,由父结点产生子结点叫扩展。完成搜索的过程就是找到一条从根结点到目标结点的路径,找出一个最优的解。这种搜索算法的实现类似于图或树的遍历,通常可以有两种不同的实现方法,即深度优先搜索(DFS——Depth First search)和广度优先搜索(BFS——Breadth First Search)。

而BFS和DFS又有什么区别呢?
宽度优先搜索算法(又称广度优先搜索)是最简便的图的搜索算法之一,这一算法也是很多重要的图的算法的原型。Dijkstra单源最短路径算法和Prim最小生成树算法都采用了和宽度优先搜索类似的思想。其别名又叫BFS,属于一种盲目搜寻法,目的是系统地展开并检查图中的所有节点,以找寻结果。换句话说,它并不考虑结果的可能位置,彻底地搜索整张图,直到找到结果为止。简单的来说它就是从一个点散发出去的很多条路,但是每一步他们都是同步的。

深度优先搜索(Depth-First-Search)是搜索算法的一种。是沿着树的深度遍历树的节点,尽可能深的搜索树的分支。当节点v的所有边都己被探寻过,搜索将回溯到发现节点v的那条边的起始节点。这一过程一直进行到已发现从源节点可达的所有节点为止。如果还存在未被发现的节点,则选择其中一个作为源节点并重复以上过程,整个进程反复进行直到所有节点都被访问为止。属于盲目搜索。简单的来说,它就是从一个点散发一条路,一直走到尽头,如果没有到达终点,又会回溯到原来的位置,在散发出另一条路。

BFS所用的是队列,将符合条件的点放进队列中,队列采用先进先出的原则,先放进来的那个点,在取出来的时候也是先取出。
DFS所用的是递归函数,而函数所占的内存空间为栈,如果所给的的矩阵不能过大。不然就会爆栈。所以我们一般都使用BFS.


下面我们给出DFS的代码模板    当然我们需要找一个例题

Red and Black
                               Time Limit:1000MS    Memory Limit:32768KB    64bit IO Format:%I64d & %I64u

Description

There is a rectangular room, covered with square tiles. Each tile is colored either red or black. A man is standing on a black tile. From a tile, he can move to one of four adjacent tiles. But he can't move on red tiles, he can move only on black tiles.

Write a program to count the number of black tiles which he can reach by repeating the moves described above.
 

Input

The input consists of multiple data sets. A data set starts with a line containing two positive integers W and H; W and H are the numbers of tiles in the x- and y- directions, respectively. W and H are not more than 20.

There are H more lines in the data set, each of which includes W characters. Each character represents the color of a tile as follows.

'.' - a black tile
'#' - a red tile
'@' - a man on a black tile(appears exactly once in a data set)
 

Output

For each data set, your program should output a line which contains the number of tiles he can reach from the initial tile (including itself).
 

Sample Input

     
6 9 ....#. .....# ...... ...... ...... ...... ...... #@...# .#..#. 11 9 .#......... .#.#######. .#.#.....#. .#.#.###.#. .#.#..@#.#. .#.#####.#. .#.......#. .#########. ........... 11 6 ..#..#..#.. ..#..#..#.. ..#..#..### ..#..#..#@. ..#..#..#.. ..#..#..#.. 7 7 ..#.#.. ..#.#.. ###.### ...@... ###.### ..#.#.. ..#.#.. 0 0
 

Sample Output

     
45 59 6 13
  这是一道简单的搜索。就是查找它从@可以到达的位置有多少个点,因为是n<20,所以不会爆栈,下面是DFS的代码
<span style="color:#000000;">#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <stack>
using namespace std;
char map1[30][30];//用来存储图形的点
int dx[]={0,0,1,-1};//用来走上下位置
int dy[]={1,-1,0,0};//用来走左右位置
int n,m,ans=0;
void dfs(int x,int y)
{
    if(x<1||x>n||y<1||y>m)return ;//判断  如果移动之后没有越界。就继续
    if(map1[x][y]=='#')return;//如果遇到墙,则推出递归
    ++ans//如果上面两种情况都满足的话,就总数+1
    map1[x][y]='#';//将走过的地方标记,防止再走回来,从而进行无限的递归
    for(int i=0;i<4;i++)
    dfs(x+dx[i],y+dy[i]);//往四个方向移动
}
int main()
{
    while(~scanf("%d%d",&m,&n)&&(n||m))
    {
        ans=0;
        int sx,sy;
        for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            scanf(" %c",&map1[i][j]);
            if(map1[i][j]=='@')
            sx=i,sy=j;//保存起始点
        }
        dfs(sx,sy);
        printf("%d\n",ans);
    }
    return 0;
}</span>

下面是另一种算法BFS,代码如下:
<span style="color:#000000;">#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <stack>
using namespace std;
struct point
{
    int x,y,step;
}st;//构造一个结构体。step代表走的步数
queue <point> q;
char map1[30][30];
int vis[30][30];//标记数组,初始话为0,如果一个点走过,就标记为1,或者标记为走的步数,当移动的时候判断vis是否为0,如果不为0的话,则跳过;
int dx[]={0,0,1,-1};
int dy[]={1,-1,0,0};
int n,m;
int bfs(){
    while(!q.empty())q.pop();//这是队列函数,q.empty() 是判断队列里面是否为空,q.pop()是把队列中第一个元素丢掉
    memset(vis,0,sizeof(vis));
    vis[st.x][st.y]=1;//将起始点标记
    q.push(st);//q.push()为队列的函数。是讲小括号里面的值放进队列中
    int mm=0;
    while(!q.empty()){
        ++mm;
        point now=q.front();//q.front() 为取出队列的头结点
        q.pop();
        for(int i=0;i<4;i++){
            point next=now;
            next.x+=dx[i];next.y+=dy[i];//上下左右移动
            ++next.step;
            if(next.x<1||next.x>n
               ||next.y<1||next.y>m)continue;//判断是否满足条件
            if(map1[next.x][next.y]=='#')continue;
            if(vis[next.x][next.y])continue;
            vis[next.x][next.y]=1;//如果满足条件 。则把那个点放进队列中,并标记为1,代表走过。
            q.push(next);
        }
    }
    return mm;
}
int main()
{
    while(~scanf("%d%d",&m,&n)&&(n||m)){
        for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            scanf(" %c",&map1[i][j]);
            if(map1[i][j]=='@'){
                st.x=i;st.y=j;st.step=0;
            }
        }
        printf("%d\n",bfs());
    }
    return 0;
}</span>

谢谢看完。如果有什么意见和建议。欢迎提出!





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值