导航

广度优先搜索

Posted on 2018-08-17 14:29  困或  阅读(329)  评论(0编辑  收藏  举报

1.算法说明

  [1]广度优先搜索算法(BFS)主要用于计算源点到目标点的最短路径。

  [2]BFS的基本实现是使用队列,从源点开始入队列,访问后把临近节点入队列,之后出队列,再访问刚加进的临近节点,以此反复访问,知道达到目标点。

2.算法步骤

  1. 首先将根节点放入队列中。

  2. 从队列中取出第一个节点,并检验它是否为目标,如果找到目标,则结束搜寻并回传结果,否则将它所有尚未检验过的直接子节点加入队列中。

  3. 若队列为空,表示整张图都检查过了,此时可以返回结果,否则重复步骤2。

  更具体地:

  以白色表示未达到的节点,灰色表示边缘节点(意思是需要从这些节点继续搜索),黑色表示已经达到的节点。

  1.在搜索的过程中,初始所有节点是白色,把起点V0标志成灰色。

  2.访问所有灰色的节点的临近节点,如果临近节点是白色,则把这些临近节点变为灰色(此时判断染灰色的节点是否为目标节点,如果是则表示完成),否则表示已经到达过则不处理,并把当前节点变成黑色。

  3.重复第2步。

  

 3.例子

描述:
在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字。棋盘中留有一个空格,空格用0来表示。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765),
找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。 输入格式:   输入初试状态,一行九个数字,空格用0表示 输出格式:   只有一行,该行只有一个数字,表示从初始状态到目标状态需要的最少移动次数(测试数据中无特殊无法到达目标状态数据)

  代码:

#include<cstdio>
#include<cstring>
#include<map>
#include<stdlib.h>
using namespace std;

const int M=400000;

/*   
    每个0位置状态时,可以移动的位置
    例如0在位置0时,可以移动到1和3位置。
*/
int g_change_position[9][4]={{-1,-1,3,1},{-1,0,4,2},{-1,1,5,-1},
                    {0,-1,6,4},{1,3,7,5},{2,4,8,-1},
                    {3,-1,-1,7},{4,6,-1,8},{5,7,-1,-1}
                    };

int g_target = 123804765;

/*
    g_map用来记录状态是否达到过,如果未达到过,则加入que队列。
    如果达到过则什么都不处理。
    例如初始把起点加入队列,并且设置为该状态为1,表示已达到过。
*/
map<int,bool> g_map;

/*
    9!是362880,表示012345678这九个数字共有362880种排列组合
    [][0] :排列值
    [][1] :空位0的位置
    [][2] :到此排列状态所走的步数

    que[400000]就是BFS的队列,把将要搜索的节点放入队列,之后再顺序访问队列。
*/
int que[400000][3];

// 交换字符串中的两个位置
void swap(char *c,int a,int b){
    char t=c[a];
    c[a]=c[b];
    c[b]=t;
}

/*
    head表示队列que的起点,tail表示队列que的终点,达到终点则退出。
    初始时,把起点加入队列,此时队列长度为1,因此起点为0,终点为1。
    队列中加入新节点时,队列终点后移。
    当前状态搜索临近节点后,把临近节点加入队列,队列搜索位置后移。
*/
int bfs(int n, int p)
{
    int i, swap_pos;
    int head=0,tail=1,temp;    

    //设置起点状态达到,并且加入队列
    g_map[n]=1;

    que[head][0] = n;
    que[head][1] = p;
    que[head][2] = head;

    while(head != tail){
        char cur[10];
        int pos = que[head][1];        //当前状态0的位置
        
        sprintf(cur, "%09d", que[head][0]);

        //要交换的四个位置,上下左右
        for(i=0;i<4;i++){
            swap_pos = g_change_position[pos][i];

            if(swap_pos == -1)
                continue;

            //交换0的位置,得到新的状态,转为int,保存到temp
            swap(cur, pos, swap_pos);
            sscanf(cur,"%d",&temp);
            if(temp == g_target)
                return que[head][2] + 1;

            //如果 新的状态没有出现过,则将这个新状态加到map
            if(g_map.count(temp) == 0){
                que[tail][0]=temp;
                que[tail][1]=swap_pos;
                que[tail][2]=que[head][2]+1;
                
                tail++;    
                g_map[temp] = 1;
            }

            //一个新状态处理完了一定要记得将交换的0交换回来 
            swap(cur, pos, swap_pos);
        }
        
        head++;
    }
}

int main()
{
    int n, i = -1, count = 0;
    char start[10];

    printf("input start array: ");
    scanf("%s", start);

    n = atoi(start);
    
    while(start[++i] != '0');        //查找初始状态0的位置 

    if(n != g_target)
        count = bfs(n, i); 

    printf("%d", count);
    return 0;
}

  [1]BFS搜索时,最基本是用了队列que来保存已到达的状态,之后顺序访问队列,把新状态再加到队列中。