广搜与深搜



深搜和广搜--原理彼此的优缺点


一般来说,广搜常用于找单一的最短路线,或者是规模小的路径搜索,它的特点是"搜到就是最优解", 而深搜用于找多个解或者是"步数已知(好比3步就必需达到前提)"的标题,它的空间效率高,然则找到的不必定是最优解,必需记实并完成全数搜索,故一般情况下,深搜需要很是高效的剪枝(优化).


像搜索最短路径这些的很显著是用广搜,因为广搜的特征就是一层一层往下搜的,保证当前搜到的都是最优解,当然,最短路径只是一方面的操作,像什么起码状态转换也是可以操作的。
深搜就是优先搜索一棵子树,然后是另一棵,它和广搜对比,有着内存需要相对较少的所长,八皇后标题就是典范楷模的操作,这类标题很显著是不能用广搜往解决的。或者像图论里面的找圈的算法,数的前序中序后序遍历等,都是深搜


深搜和广搜的分歧之处是在于搜索次序的分歧。


深搜的实现近似于栈,每次选择栈顶元素往扩年夜,


广搜则是操作了队列,先被扩年夜的的节点优先拿往扩年夜。


搜索树的形态:深搜层数良多,广搜则是很宽。


深搜合适找出所有方案,广搜则用来找出最佳方案


深搜和广搜的分歧:


深搜并不能保证第一次碰着方针点就是最短路径,是以要搜索所有可能的路径,是以要回溯,标识表记标帜做了之后还要打消失踪,是以统一个点可能被访谒良多良多次。而广搜因为它的由近及远的结点扩年夜次序,结点老是以最短路径被访谒。一个结点假如第二次被访谒,第二次的路径确定不会比第一次的短,是以就没有需要再从这个结点向周围扩年夜――第一次访谒这个结点的时辰已经扩年夜过了,第二次再扩年夜只会获得更差的解。是以做过的标识表记标帜不必往失踪。是以统一个点至多只可能被访谒一次。每访谒一个结点,与它相连的边就被搜检一次。是以最坏情况下,所有边都被搜检一次,是以时刻复杂度为O(E)。


BFS与DFS的讨论:BFS:这是一种基于队列这种数据结构的搜索方式,它的特点是由每一个状态可以扩展出许多状态,然后再以此扩展,直到找到目标状态或者队列中头尾指针相遇,即队列中所有状态都已处理完毕。
DFS:基于递归的搜索方式,它的特点是由一个状态拓展一个状态,然后不停拓展,直到找到目标或者无法继续拓展结束一个状态的递归。
         
优缺点:BFS:对于解决最短或最少问题特别有效,而且寻找深度小,但缺点是内存耗费量大(需要开大量的数组单元用来存储状态)。
        DFS:对于解决遍历和求所有问题有效,对于问题搜索深度小的时候处理速度迅速,然而在深度很大的情况下效率不高
 
总结:不管是BFS还是DFS,它们虽然好用,但由于时间和空间的局限性,以至于它们只能解决数据量小的问题。
 
各种搜索题目归类:
 
坐标类型搜索 :这种类型的搜索题目通常来说简单的比较简单,复杂的通常在边界的处理和情况的讨论方面会比较复杂,分析这类问题,我们首先要抓住题目的意思,看具体是怎么建立坐标系(特别重要),然后仔细分析到搜索的每一个阶段是如何通过条件转移到下一个阶段的。确定每一次递归(对于DFS)的回溯和深入条件,对于BFS,要注意每一次入队的条件同时注意判重。要牢牢把握目标状态是一个什么状态,在什么时候结束搜索。还有,DFS过程的参数如何设定,是带参数还是不带参数,带的话各个参数一定要保证能完全的表示一个状态,不会出现一个状态对应多个参数,而这一点对于BFS来说就稍简单些,只需要多设置些变量就可以了。
              经典题目:细胞(NDK1435)、Tyvj:乳草的入侵、武士风度的牛
 
数值类型搜索:(虽然我也不知道该怎么叫,就起这个名字吧),这种类型的搜索就需要仔细分析分析了,一般来说采用DFS,而且它的终止条件一般都是很明显的,难就难在对于过程的把握,过程的把握类似于坐标类型的搜索(判重、深入、枚举),注意这种类型的搜索通常还要用到剪枝优化,对于那些明显不符合要求的特殊状态我们一定要在之前就去掉它,否则它会像滚雪球一样越滚越大,浪费我们的时间。










最短路问题------分别用深搜和广搜去解题


最少步数
时间限制:3000 ms  |  内存限制:65535 KB
难度:4
描述
这有一个迷宫,有0~8行和0~8列:


 1,1,1,1,1,1,1,1,1
 1,0,0,1,0,0,1,0,1
 1,0,0,1,1,0,0,0,1
 1,0,1,0,1,1,0,1,1
 1,0,0,0,0,1,0,0,1
 1,1,0,1,0,1,0,0,1
 1,1,0,1,0,1,0,0,1
 1,1,0,1,0,0,0,0,1
 1,1,1,1,1,1,1,1,1


0表示道路,1表示墙。


现在输入一个道路的坐标作为起点,再如输入一个道路的坐标作为终点,问最少走几步才能从起点到达终点?


(注:一步是指从一坐标点走到其上下左右相邻坐标点,如:从(3,1)到(4,1)。)


输入
第一行输入一个整数n(0 随后n行,每行有四个整数a,b,c,d(0<=a,b,c,d<=8)分别表示起点的行、列,终点的行、列。
输出
输出最少走几步。
样例输入
3 1  5 7
1  6 7
样例输出
11




广度优先搜索特点是从一个点开始以圆形的方式 向周围  开始扩散广搜常用于找单一的最短路线,或者是规模小的路径搜索,它的特点是"搜到就是最优解广搜则是操作了队列,先被扩年夜的的节点优先拿往扩年夜。
//   广搜  每个点走一边 就得到了   从原点 到  终点的 最短距离
#include
#include
#include
#include
#include
using namespace std;
int a[9][9]=
{
    1,1,1,1,1,1,1,1,1,
    1,0,0,1,0,0,1,0,1,
    1,0,0,1,1,0,0,0,1,
    1,0,1,0,1,1,0,1,1,
    1,0,0,0,0,1,0,0,1,
    1,1,0,1,0,1,0,0,1,
    1,1,0,1,0,1,0,0,1,
    1,1,0,1,0,0,0,0,1,
    1,1,1,1,1,1,1,1,1
};
struct node
{
    int x,y,step;  //节点的坐标和 距离起点 路程
};
queue Q;
int c[4]={0,0,-1,1},b[4]={-1,1,0,0},visite[9][9];
int bfs(int x1,int y1,int x2,int y2)
{
    int i,s,t;
    node e={x1,y1,0};   //  从这一点开始走
    visite[x1][y1]=1;
    Q.push(e);   //     原点  压进去
    while(!Q.empty())
    {
        e=Q.front();     //  队首 元素  取出来
        if(e.x==x2&&e.y==y2)
        {
            break;    //跳出去的时候   节点e  就是   终点
        }
        Q.pop();
        for(i=0;i<4;i++)
        {
            s=e.x+c[i];
            t=e.y+b[i];
            if(s<=8&&s>=0&&t>=0&&t<=8&&!visite[s][t]&&!a[s][t])
            {
                node e1={s,t,e.step+1};
                Q.push(e1);
                visite[s][t]=1;
            }
        }
    }
    if(Q.empty())
        return -1;
    while(!Q.empty())
        Q.pop();
    return e.step;
}
int main()
{
    int k,n,x1,x2,y1,y2;
    scanf("%d",&n);
    while(n--)
    {
        memset(visite,0,sizeof(visite));
        scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
        k=bfs(x1,y1,x2,y2);
        printf("%d\n",k);
    }
    return 0;
}
/
/
#include
int ans,sx,sy,ex,ey;
bool vis[9][9],map[9][9]=
{
    1,1,1,1,1,1,1,1,1,
    1,0,0,1,0,0,1,0,1,
    1,0,0,1,1,0,0,0,1,
    1,0,1,0,1,1,0,1,1,
    1,0,0,0,0,1,0,0,1,
    1,1,0,1,0,1,0,0,1,
    1,1,0,1,0,1,0,0,1,
    1,1,0,1,0,0,0,0,1,
    1,1,1,1,1,1,1,1,1
};


void dfs(int i,int j,int cnt)
{
    if(i<0||i>8||j<0||j>8||vis[i][j]||map[i][j]||cnt>=ans)
        return;
    if(i==ex&&j==ey)
    {
        ans=cnt;
        return;
    }
    vis[i][j]=1;       // 这个已经遍历了x`
    dfs(i,j-1,cnt+1);
    dfs(i-1,j,cnt+1);
    dfs(i,j+1,cnt+1);
    dfs(i+1,j,cnt+1);


    vis[i][j]=0;
}


int main()
{
    int n;
    scanf("%d",&n);
    while(n--)
    {
        scanf("%d%d%d%d",&sx,&sy,&ex,&ey);
        ans=100;
        dfs(sx,sy,0);
        printf("%d\n",ans);
    }
    return 0;
}


【题意】
汉语意思不再解释。
【思路】
深搜+记录路径。
这里叙述一下深搜与广搜记录路径的不同之处。(个人观点)
深搜来说,记录路径只需要一个普通数组,因为深搜可以返回。
广搜的话,需要在结构体里开数组,因为广搜的每一步都会产生一个新的组合。
【代码】


#include
#include
#include
#include
#include
#include
#include
#include
#include
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
const int INF=1e9;
typedef long long LL;
int num=0,m;;
struct pp
{
    int a[3];
}z[23];
int load[25];
bool vis[25];
void dfs(int x,int t)
{
    if(x==m&&t!=0)
    {
        if(t!=20)
            return ;//剪枝
        printf("%d:  %d",++num,m);
        for(int i=1;i<=20;i++)
            printf(" %d",load[i]);
        printf("\n");
        return ;
    }
    for(int i=0;i<3;i++)
    {
        if(!vis[z[x].a[i]])
        {
            vis[z[x].a[i]]=1;
            load[t+1]=z[x].a[i];
            dfs(z[x].a[i],t+1);
            vis[z[x].a[i]]=0;//取消标记
        }
    }
}
int main()
{
    for(int i=1;i<=20;i++)
        scanf("%d%d%d",&z[i].a[0],&z[i].a[1],&z[i].a[2]);
    while(~scanf("%d",&m))
    {
        if(!m)
            break;
        mem(vis,0);
        dfs(m,0);
    }
}






    #include  
    #include  
    #include  
    using namespace std;  
    int go[4][2]= {1,0,-1,0,0,1,0,-1};  
    int map[1005][1005];  
    struct gg  
    {  
        int x,y,step;  
    };  
    gg road[1000][1000];  
    gg aa[100];  
    queueq;  
    void fg(int xx,int yy)  
    {  
        int a,b,i=0;  
        while(xx!=0||yy!=0)  
        {  
            a=xx,b=yy;  
            aa[i].x=road[a][b].x;//记录上一个点;  
            aa[i++].y=road[a][b].y;  
            xx=road[a][b].x;  
            yy=road[a][b].y;  
        }  
        for(i--; i>=0; i--)  
            printf("(%d, %d)\n",aa[i].x,aa[i].y);  
        printf("(4, 4)\n");  
        return;  
    }  
    void ff()  
    {  
        gg n1,n2;  
        n1= {0,0,0};  
        q.push(n1);  
        map[0][0]=1;  
        while(!q.empty())  
        {  
            n1=q.front();  
            if(n1.x==4&&n1.y==4)  
            {  
                fg(4,4);  
                return ;  
            }  
            q.pop();  
            for(int h=0; h<4; h++)  
            {  
                int xx=n1.x+go[h][0],yy=n1.y+go[h][1];  
                if(xx>=0&&xx<=4&&yy>=0&&yy<=4&&map[xx][yy]==0)  
                {  
                    map[xx][yy]=1;  
                    n2= {xx,yy,n1.step+1};  
                    q.push(n2);  
                    road[xx][yy].x=n1.x;  
                    road[xx][yy].y=n1.y;  
                }  
            }  
        }  
    }  
    int main()  
    {  
        int i,j;  
        for(i=0; i<5; i++)  
            for(j=0; j<5; j++)  
                scanf("%d",&map[i][j]);  
        ff();  
        return 0;  

    }  


输入一个地图:
1代表墙,0代表可以走
输入开始位置和结束位置
输出,最短步数。

#include
using namespace std;
int arr[51][51],book[51][51];
int m,n,endx,endy,team=999999;
void dfs(int x,int y,int step){
    /// 四种位移,上下左右 
    int next[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
    if(x==endx&&y==endy){
        if(team>step)
            team=step;
        return ;
    }else{
        for(int k=0;k<4;k++){
            int tx=x+next[k][0];
            int ty=y+next[k][1];
            //首先判断是否越界
            if(tx<0||ty<0||tx>=m||ty>=m)
                continue; 
            if(book[tx][ty]==0&&arr[tx][ty]==0){
                book[tx][ty]=1;// 标记表示走过 
                dfs(tx,ty,step+1);
                book[tx][ty]=0;//  退回 
            }
        }
    }
    return ;
}
int main(){
    cin>>m>>n;
    for(int i=0;ifor(int j=0;jcin>>arr[i][j];
    // 出发位置 
    int startx,starty;
    cin>>startx>>starty>>endx>>endy;
    book[startx][starty]=1;
    dfs(startx,starty,0);
    cout<return 0;
}


你可能感兴趣的:(IT,搜索)