深搜和广搜(初学者)

搜索入门

    最近对搜索有了一点浅显的了解,想跟大家分享分享。
    说起来我也是初学者,恰巧有些自己的理解,想起来自己开始学习搜索的情况,真是一把鼻子一把泪啊。所以想把我领悟的过程,看到的一些基础的我觉得好的东西总结一下。
    谈到搜索,都会想到深搜和广搜,先来说一下基础算法——回溯算法,其实深搜用的就是回溯算法。

    一、回溯算法

          回溯算法是搜索算法中的一种基础算法。用的是“走不通就掉头”的思想。我想大家也不喜欢看文字吧,看的烦不说,还难理解,那我就用图片来展示一下回溯的过程。


    具体应用结合一道简单题目: 点击打开链接

Oil Deposits

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.
 

Input

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.
 

Output

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.
 

Sample Input

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

Sample Output
  
  
0 1 2 2

题目大意:寻找油田数,@代表油田,如果相邻或对角相邻则属于同一块油田,求油田数目。
代码:

#include<bits/stdc++.h>
using namespace std;
int a,b;
char q[20][20];
void su(int x,int y)
{
    int dx,dy;
    q[x][y]='*';//将走过的改为'*'
    for(int i=-1;i<=1;i++)
    {
        for(int j=-1;j<=1;j++)
        {
            dx=x+i;
            dy=y+j;
            if(dx>=0&&dx<a&&dy>=0&&dy<b&&q[dx][dy]=='@')
                su(dx,dy);
        }
    }
    //下面八个if和上面两个for循环效果相同,不过更容易理解一些。
    /*if(x-1>=0&&q[x-1][y]=='@')//向上
    {
        su(x-1,y);
    }
    if(x+1<a&&q[x+1][y]=='@')//向下
    {
        su(x+1,y);
    }
    if(y-1>=0&&q[x][y-1]=='@')//向左
    {
        su(x,y-1);
    }
    if(y+1<b&&q[x][y+1]=='@')//向右
    {
        su(x,y+1);
    }
    if(x-1>=0&&y-1>=0&&q[x-1][y-1]=='@')//左斜向上
    {
        su(x-1,y-1);
    }
    if(x+1<a&&y-1>=0&&q[x+1][y-1]=='@')//左斜向下
    {
        su(x+1,y-1);
    }
    if(y+1<b&&x-1>=0&&q[x-1][y+1]=='@')//右斜向上
    {
        su(x-1,y+1);
    }
    if(y+1<b&&x+1<a&&q[x+1][y+1]=='@')//右斜向下
    {
        su(x+1,y+1);
    }* /
    //return ;利用递归后退,每走到无路可走就后退。
}
int main()
{
    int i,j,sum;
    while(cin>>a>>b,a!=0&&b!=0)
    {
        sum=0;
    for(i=0;i<a;i++)
    {
        for(j=0;j<b;j++)
        {
            cin>>q[i][j];
        }
    }
    for(i=0;i<a;i++)
    {
        for(j=0;j<b;j++)
        {
            if(q[i][j]=='@')
            {
                su(i,j);
                sum++;
            }
        }
    }
    cout<<sum<<endl;
    }
    return 0;
}

    二、广搜

       先看一下广搜过程:    



    广搜是层次性搜索,记录了每一步所能到达的所有状态,当先出现的状态搜索完毕再搜索下一步能到达的状态。
    看一道题目:点击打开链接
   

Knight Moves

Problem Description

A friend of you is doing research on the Traveling Knight Problem (TKP) where you are to find the shortest closed tour of knight moves that visits each square of a given set of n squares on a chessboard exactly once. He thinks that the most difficult part of the problem is determining the smallest number of knight moves between two given squares and that, once you have accomplished this, finding the tour would be easy.
Of course you know that it is vice versa. So you offer him to write a program that solves the "difficult" part.

Your job is to write a program that takes two squares a and b as input and then determines the number of knight moves on a shortest route from a to b.
 

Input

The input file will contain one or more test cases. Each test case consists of one line containing two squares separated by one space. A square is a string consisting of a letter (a-h) representing the column and a digit (1-8) representing the row on the chessboard.
 

Output

For each test case, print one line saying "To get from xx to yy takes n knight moves.".
 

Sample Input

  
  
e2 e4 a1 b2 b2 c3 a1 h8 a1 h7 h8 a1 b1 c3 f6 f6
 

Sample Output

  
  
To get from e2 to e4 takes 2 knight moves. To get from a1 to b2 takes 4 knight moves. To get from b2 to c3 takes 2 knight moves. To get from a1 to h8 takes 6 knight moves. To get from a1 to h7 takes 5 knight moves. To get from h8 to a1 takes 6 knight moves. To get from b1 to c3 takes 1 knight moves. To get from f6 to f6 takes 0 knight moves.

题目大意:国际象棋的马,也就是knight,马走日,不蹩蹄。找到从xx到xx最少需要移动的次数。

在代码之前先说一下这个:int to[8][2]={1,-2,2,-1,2,1,1,2,-1,2,-2,1,-2,-1,-1,-2};//马的八个移动方向
这么写应该更容易理解些:
to[0][2]={1,-2};
to[1][2]={2,-1};
to[2][2]={2,1};
to[3][2]={1,2};
to[4][2]={-1,2};
to[5][2]={-2,1};
to[6][2]={-2,-1};
to[7][2]={-1,-2};

  比如一坐标点(x,y),移动之后的坐标就是(x+1,y-2),(x+2,y-1),(x+2,y+1),(x+1,y+2)等等。。。看懂了吧,这就是定义to数组的意义。
上代码:
#include<bits/stdc++.h>
using namespace std;

int x2,y2,num;
int to[8][2]={1,-2,2,-1,2,1,1,2,-1,2,-2,1,-2,-1,-1,-2};
int q[10][10];
char a,b,c,d;

struct place
{
    int x,y,moves;
};
int check(int x,int y)
{
    if(x<0||y<0||x>7||y>7||q[x][y]==1)
        return 1;
        return 0;
}
int bfs()
{
    place n,m,next;
    queue<place>w;
    memset(q,0,sizeof(q));
    n.x=a-'a';
    n.y=b-'1';
    n.moves=0;
    x2=c-'a';
    y2=d-'1';
    q[n.x][n.y]=1;
    w.push(n);
    while(!w.empty())
    {
        m=w.front();
        w.pop();
        if(m.x==x2&&m.y==y2)
            return m.moves;
        for(int i=0;i<8;i++)
        {
            next.x=m.x+to[i][0];
            next.y=m.y+to[i][1];
            if(next.x==x2&&next.y==y2)
            return m.moves+1;
            if(check(next.x,next.y))
            continue;
            next.moves=m.moves+1;
            q[next.x][next.y]=1;
            w.push(next);
        }
    }
}
int main()
{
    while(scanf("%c%c %c%c",&a,&b,&c,&d)!=EOF)
    {
        getchar();
        num=bfs();
        printf("To get from %c%c to %c%c takes %d knight moves.\n",a,b,c,d,num);
    }
    return 0;
}









  • 11
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值