搜索算法思考

概述:本文主要讲述一些搜索算法的使用,以及其中奥妙思想的思考。

一:广度搜索与深度搜索---BFS与DFS

1:实现算法导论中的BSF

0s0-830394249IMAG0620

#include <deque> 
#define MAX 1000000
struct Node
{
    int d;
    int p;
    int color;
    int id;
};
int _tmain(int argc, _TCHAR* argv[])
{
    Node arrNode[8];
    int arrGrid[8][8];
    deque<Node> q;
    for(int i=0;i<8;i++)
    {
        arrNode[i].color=0;
        arrNode[i].d=MAX;
        arrNode[i].p=MAX;
        arrNode[i].id=i;
    }
    for(int i=0;i<8;i++)
        for(int j=0;j<8;j++)
            arrGrid[i][j]=0;

    arrGrid[0][1]=1;
    arrGrid[0][3]=1;
    arrGrid[1][2]=1;
    arrGrid[3][4]=1;
    arrGrid[3][5]=1;
    arrGrid[4][5]=1;
    arrGrid[4][6]=1;
    arrGrid[5][6]=1;
    arrGrid[5][7]=1;
    arrGrid[6][7]=1;




    arrNode[0].color=1;
    arrNode[0].d=0;
    q.push_back(arrNode[0]);
    while(!q.empty())
    {
        Node u=q.front();
        q.pop_front();
        for(int i=0;i<8;i++)
        {
            if(arrGrid[u.id][i]==1||arrGrid[i][u.id]==1)
            {
                Node v=arrNode[i];
                if(v.color==0)
                {
                    arrNode[v.id].color=1;
                    arrNode[v.id].p=u.id;
                    arrNode[v.id].d=u.d+1;
                    q.push_back(arrNode[v.id]);
                }
                arrNode[u.id].color=2;
            }
        }
    }

    return 0;
}

2:实现算法导论中的DSF

0s0-18328534941403702267422

int Map[6][6];
int Visit[6];
int Pre[6];
int Dis[6];
int Fin[6];
int time;

void DFS();
void DFSVisit(int u);
int _tmain(int argc, _TCHAR* argv[])
{
    for(int i=0;i<6;i++)
        for(int j=0;j<6;j++)
            Map[i][j]=0;
    Map[0][1]=1;
    Map[0][2]=1;
    Map[1][3]=1;
    Map[2][1]=1;
    Map[3][2]=1;
    Map[4][3]=1;
    Map[4][5]=1;
    Map[5][5]=1;


    for(int i=0;i<6;i++)
    {
        Visit[i]=0;
        Pre[i]=-1;
        Dis[i]=0;
        Fin[i]=0;
    }
    time=0;

    DFS();

    for(int i=0;i<6;i++)
    {
        cout<<Dis[i]<<"/"<<Fin[i]<<" ";
    }
    cout<<endl;
    for(int i=0;i<6;i++)
    {
        cout<<Pre[i]<<" ";
    }
    cout<<endl;
    char cc;
    cin>>cc;
    return 0;
}
//6个点的深度DFS;;;;
void DFS()
{
    for(int u=0;u<6;u++)
        if(Visit[u]==0)
            DFSVisit(u);
}
void DFSVisit(int u)
{
    Visit[u]=1;//表示灰色
    time++;
    Dis[u]=time;
    for(int i=0;i<6;i++)
    {
        if(Visit[i]==0&&Map[u][i]>0)
        {
            Pre[i]=u;
            DFSVisit(i);
        }
    }
    Visit[u]=2;//为黑色
    time++;
    Fin[u]=time;
}

共同点思想:不会陷入死循环,通过标记为黑而达到;都会搜索到通过非白达到。也就是需要达到全部搜索到则需要对节点标识位;使用结构体数据结构表示,用矩阵表示图;

不同点:BSF是一层一层的搜索,每次弄一次层,就必须知道该层所有房间;

DFS是像走迷宫,直到碰到墙位置才停住,而返回前一个元素,选择没有走过的路。这样可以全部走完整个地图。

搜索:这种适合枚举中选出自己想要的情况。

第二:Bellman_Ford算法与Dijkstra算法

1:Bellman_Ford算法

思想:从某个源头出发,寻找到达各个点的最小距离。会得到一个最小路径的树;

显然:该最小路径中,不能存在环,比如是正环,则通过取掉一条边而导致会变小,从而矛盾;

         若为负环:则通过不断走环值,也会导致值变小,而矛盾。

那么最小路径存在可能性就是不存在环路,那么这个最小路径表明是简单路径,对于点是V个的,又是简单路径,显然二点只有一个路径,则只能是V-1个边了。----针对这V-1个边,是路径中最小的情况,那么通过松弛,由于每次松弛都会得到一个边,故而需要V-1次松弛。由于V-1次松弛就能够得到V-1边。每次松弛都是对整个边的。

复杂度是O(VE)

实现思想:边用结构体来表示;点结构体的数组表示含有前驱和距离,下标为点标号;通过V-1次松弛达到求出了每个点的最小距离,以及一颗最小路径树。---可以判断出是否存在最小路径,可以求出最小路径-----且对边权值没有要求,有向。

实现如下:

#define MAX 1000000
struct Node
{
    int d;
    int p;
};
struct Edge
{
    int u;
    int v;
    int w;
};

int _tmain(int argc, _TCHAR* argv[])
{
    Node node[5];
    Edge edge[10];
    
    for(int i=0;i<5;i++)
    {
        node[i].d=MAX;
        node[i].p=MAX;
    }
    node[0].d=0;//
    
    edge[0].u=0;
    edge[0].v=1;
    edge[0].w=6;
    
    edge[1].u=0;
    edge[1].v=2;
    edge[1].w=7;

    edge[2].u=1;
    edge[2].v=3;
    edge[2].w=5;

    edge[3].u=1;
    edge[3].v=4;
    edge[3].w=-4;

    edge[4].u=1;
    edge[4].v=2;
    edge[4].w=8;
    
    edge[5].u=2;
    edge[5].v=3;
    edge[5].w=-3;

    edge[6].u=2;
    edge[6].v=4;
    edge[6].w=9;

    edge[7].u=3;
    edge[7].v=1;
    edge[7].w=-2;

    edge[8].u=4;
    edge[8].v=0;
    edge[8].w=2;

    edge[9].u=4;
    edge[9].v=3;
    edge[9].w=7;

    for(int i=0;i<4;i++)
    {//V-1次
        for(int j=0;j<10;j++)
        {
            int sum=node[edge[j].u].d+edge[j].w;
            if(sum<node[edge[j].v].d)
            {
                node[edge[j].v].d=sum;
                node[edge[j].v].p=edge[j].u;
            }
        }
    }

    for(int j=0;j<10;j++)
    {
        int sum=node[edge[j].u].d+edge[j].w;
        if(sum<node[edge[j].v].d)
        {
            cout<<"False"<<endl;
            return 0;
        }
    }
    cout<<"True"<<endl;

    return 0;
}

2:Dijkstra算法

思想:该算法没有上个算法通用,但是效率高,时间复杂度可达到O(Vlg(V)+E);但是有限定,就是权重不能为负值。

过程思想:从源头出发,对每个节点处的边松弛,直到最后。由于是正值,所以又是从源头开始的,一旦确定它了,那么它就是最小距离了,因为不会通过环而让其更小了,这是因为没有负值的边。-----每次确定是取没有确定的最小值作为这个确定值。

实现如下:

#define MAX 1000000
struct Node
{
    int d;
    int p;
    int color;
};

int _tmain(int argc, _TCHAR* argv[])
{
    int edge[5][5];
    for(int i=0;i<5;i++)
        for(int j=0;j<5;j++)
            edge[i][j]=MAX;
    edge[0][1]=10;
    edge[0][2]=5;
    edge[1][2]=2;
    edge[1][3]=1;
    edge[2][1]=3;
    edge[2][3]=9;
    edge[2][4]=2;
    edge[3][4]=4;
    edge[4][0]=7;
    edge[4][3]=6;

    Node node[5];
    for(int i=0;i<5;i++)
    {
        node[i].d=MAX;
        node[i].p=MAX;
        node[i].color=0;
    }
    node[0].d=0;
    


    for(int i=0;i<5;i++)
    {
    //取最小值
        int minid;
        int min=MAX+100;
        for(int j=0;j<5;j++)
        {
            if(min>node[j].d&&node[j].color==0)
            {
                min=node[j].d;
                minid=j;
            }
        }

        node[minid].color=1;
        //松弛
        for(int j=0;j<5;j++)
        {
            if(edge[minid][j]+node[minid].d<node[j].d&&node[j].color==0)
            {
                node[j].d=edge[minid][j]+node[minid].d;
                node[j].p=minid;
                
            }
        }
    }


    return 0;
}
原文地址:https://www.cnblogs.com/miner007/p/3811586.html