双向BFS

本文介绍了一种利用双向广度优先搜索算法优化路径查找效率的方法,通过同时从开始状态和结束状态双向搜索,减少搜索状态数量,显著提高路径查找速度。适用于已知搜索开始状态和结束状态的情况,特别在分支因子较大时效果更佳。

转自:http://blog.sina.com.cn/s/blog_6635898a0100p4wd.html

如果已经知道搜索的开始状态和结束状态,要找一个满足某种条件的一条路径(一般是最短路径),为了避免无谓的“组合爆炸”产生,就可以采取双向广度搜索算法,也就是从开始状态和结束状态同时开始搜索,一个向前搜,一个向后找。 

这样做的好处是什么?
    我们不妨假设每次搜索的分支因子是r,如果最短的路径长为L的话(也就是搜了L层),那么,用一般的BFS算法(不考虑去掉重复状态),总的搜索状态数是r^L(^表示乘方运算);而如果采取双向BFS算法,那么,从前往后搜,我们只需要搜索L/2层,从后往前搜,我们也只要搜L/2层,因此,搜索状态数是2*(r^(L/2)),比普通BFS就快了很多了。 

    双向BFS算法的实质还是BFS,只不过两边同时开始BFS而已。还是可以利用队列来实现:可以设置两个队列,一个用于向前的BFS,另一个用于向后的BFS,利用这两个队列,同时从前、后开始层次遍历搜索树。

 

双向bfs(转载)


下面转自:http://www.cppblog.com/Yuan/archive/2011/02/23/140553.aspx

如果目标也已知的话,用双向BFS能很大提高速度

单向时,是 b^len的扩展。

双向的话,2*b^(len/2)  快了很多,特别是分支因子b较大时

至于实现上,网上有些做法是用两个队列,交替节点搜索 ×,如下面的伪代码:
    while(!empty()){

            扩展正向一个节点

           遇到反向已经扩展的return

        扩展反向一个节点      

            遇到正向已经扩展的return      

      }

但这种做法是有问题的,如下面的图:


求S-T的最短路,交替节点搜索(一次正向节点,一次反向节点)时

Step 1 : S –> 1 , 2

Step 2 : T –> 3 , 4

Step 3 : 1 –> 5

Step 4 : 3 –> 5   返回最短路为4,错误的,事实是3,S-2-4-T


 

我想,正确做法的是交替逐层搜索,保证了不会先遇到非最优解就跳出,而是检查完该层所有节点,得到最优值
也即如果该层搜索遇到了对方已经访问过的,那么已经搜索过的层数就是答案了,可以跳出了,以后不会更优的了。
当某一边队列空时就无解了。

 

优化:提供速度的关键在于使状态扩展得少一些,所以优先选择队列长度较少的去扩展,保持两边队列长度平衡。这比较适合于两边的扩展情况不同时,一边扩展得快,一边扩展得慢。如果两边扩展情况一样时,加了后效果不大,不过加了也没事。

无向图时,两边扩展情况类似。有向图时,注意反向的扩展是反过来的 x->y(如NOIP2002G2字串变换)




Code

void gao(vector<int> &from , vector<int> &to , Hash &hash) {
    to.clear();
    
for(vector<int>::iterator it = from.begin() ; it != from.end() ; it++)
{
        利用hash判重,扩展
*
it            
    }

}

int bibfs(int start , int dest) {
    
if(start == dest)
//注意要先判相等
        return 0;
    }


    Hash bfs , rbfs;
    bfs[start] 
= 0;
    rbfs[dest] 
= 0;

    vector
<int> Q[2] , rQ[2]; //用vector做队列,方便遍历

    int cur = 0 , rcur = 0;
    Q[cur].push_back(start);
    rQ[rcur].push_back(dest);

    
for(int step = 1 ; step <= limit && !Q[cur].empty() && !rQ[rcur].empty();  step++)
{
        
//cout<<step<<endl;

        if(Q[cur].size() <= rQ[rcur].size()){//优先扩展队列长度小的
            gao(Q[cur],Q[cur^1],bfs);
            cur 
^= 1;
            
for(vector<int>::iterator it = Q[cur].begin() ; it != Q[cur].end() ; it++)
{
                
if(rbfs.find(*it) != rbfs.end())
{
                    
return
 step;
                }

            }

        }
else{
            gao(rQ[rcur],rQ[rcur
^1],bfs);
            rcur 
^= 1;
            
for(vector<int>::iterator it = rQ[rcur].begin() ; it != rQ[rcur].end() ; it++)
{
                
if(bfs.find(*it) != bfs.end())
{
                    
return
 step;
                }

            }

        }

    }

    
return -1;
}



 

我用这种做法,做了几道题,都没错,速度还行。

按难度递增:
 

hdu 1195

NOIP2002G2字串变换   注意反向的扩展是反过来

ZOJ 1505

ZOJ 3467

/*
    3维中,求点(x0,y0,z0)到(x1,y1,z1)不超过步字典序最小的路径
    一步能跳(x,y,z)  组合一下有!*8 = 48种
    48^6太大了
    双向BFS 2*48^3

    参照watashi的代码写的
    STL真神奇
    vector重载了比较运算符的
    typedef map<Point , vector<Point> > Hash;

    一层一层,这样才保证正确解
    这里由于两边结构差不多,所以判断队列长度的优化效果不大
    细节较多
    我写得较挫
*/

struct  Point {
    
int x , y , z;
    Point()
{}
    Point(
int x,int y , int z):x(x),y(y),z(z){}

    
bool operator < (const Point &B)const{
        
if(x != B.x){
            
return x < B.x;
        }
else if(y != B.y){
            
return y < B.y;        
        }
else{
            
return z < B.z;
        }

    }

    
bool operator == (const Point &B)const{
        
return x == B.x && y == B.y && z == B.z;
    }

    Point 
operator +(const Point &B)const{
        
return Point(x+B.x , y+B.y, z+B.z);
    }

}
;

typedef map
< Point , vector < Point >   >  Hash;
vector
< Point >  dir;

void  init( int  x , int  y ,  int  z) {
    
int d[] = {x, y, z};
    sort(d,d
+3);
    dir.clear();
    
do{
        
for(int mask = 0 ; mask < 8 ; mask ++){
            
int nx = (mask & 1? d[0] : -d[0];
            
int ny = (mask & 2? d[1] : -d[1];
            
int nz = (mask & 4? d[2] : -d[2];
            dir.push_back(Point(nx,ny,nz));
        }

    }
while(next_permutation(d,d+3));
}


void  gao(vector < Point >   & from , vector < Point >   & to , Hash  & bfs) {
    to.clear();
    
int len = bfs[*from.begin()].size();
    
for(vector<Point>::iterator it = from.begin() ; it != from.end() ; it++){
        Hash::iterator  preIt 
= bfs.find(*it);
        
for(int k = 0 ; k < 48 ; k++){
            Point next 
= *it + dir[k];
            Hash::iterator  nextIt 
= bfs.find(next);
            
if(nextIt == bfs.end()){
                bfs[next] 
= preIt->second;
                to.push_back(next);
            }
else if(!(nextIt->second.front() == next || nextIt->second.back() == next) //注意需要判断这个,因为长度=len的可能是之前的
                && nextIt->second.size() == len && nextIt->second > preIt->second){
                nextIt
->second = preIt->second;
            }

        }

    }

}


void  bibfs(vector < Point >   & ans , Point  & start , Point  & dest) {
    
if(start == dest){
        ans.push_back(start);
        
return;
    }


    Hash bfs , rbfs;
    bfs[start].push_back(start);
    rbfs[dest].push_back(dest);

    vector
<Point> Q[2] , rQ[2];    
    
//for(int i = 0 ; i < 2 ; i ++){
    
//    Q[i].reserve(1000);
    
//    rQ[i].reserve(1000);
    
//}
    int cur = 0 , rcur = 0;
    Q[cur].push_back(start);
    rQ[rcur].push_back(dest);
    
for(int step = 0 ; ans.empty() && !Q[cur].empty() && step < 6 ; step++){
        
if(Q[cur].size() <= rQ[cur].size()){
            gao(Q[cur],Q[cur
^1],bfs);
            cur 
^= 1;
            
//chk
            for(int i = 0 ; i < Q[cur].size() ; i++){
                Point 
&val = Q[cur][i];
                Hash::iterator fit 
= bfs.find(val);
                Hash::iterator rfit 
= rbfs.find(val);
                
if(rfit != rbfs.end()){
                    vector
<Point> tmp = fit->second;                    
                    tmp.insert(tmp.end() , rfit
->second.begin(), rfit->second.end());
                    
if(ans.empty() || tmp < ans){
                        ans 
= tmp;
                    }

                }

                fit
->second.push_back(val);//push                
            }

        }
 else {
            gao(rQ[rcur],rQ[rcur
^1],rbfs);
            rcur 
^= 1;
            
//chk
            for(int i = 0 ; i < rQ[rcur].size() ; i++){
                Point 
&val = rQ[rcur][i];
                Hash::iterator rfit 
= rbfs.find(val);
                Hash::iterator fit 
= bfs.find(val);
                
if(fit != bfs.end()){
                    vector
<Point> tmp = rfit->second;                                    
                    tmp.insert(tmp.begin() , fit
->second.begin() , fit->second.end());
                    
if(ans.empty() || tmp < ans){
                        ans 
= tmp;
                    }

                }

                rfit
->second.insert(rfit->second.begin(),val);//push
            }

        }
        
    }
    
}


int  main()
{
    
//freopen("in","r",stdin);
    
//freopen("out","w",stdout);

    
int x0,y0,z0,x1,y1,z1,x,y,z;
    
while(~scanf("%d%d%d%d%d%d%d%d%d",&x0,&y0,&z0,&x1,&y1,&z1,&x,&y,&z)){

        init(x,y,z);

        vector
<Point> ans;
        Point start(x0,y0,z0) , dest(x1,y1,z1);
        bibfs(ans , start , dest);

        printf(
"To get from (%d,%d,%d) to (%d,%d,%d) takes " , x0,y0,z0,x1,y1,z1);
        
if(ans.empty()){
            printf(
"more than 6 3D knight moves (%d,%d,%d).\n",x,y,z);
        }
else{
            printf(
"%d 3D knight moves (%d,%d,%d): ",ans.size()-1,x,y,z);
            
for(int i = 0 ; i < ans.size() ; i++){
                
if(i)printf(" => ");
                printf(
"(%d,%d,%d)",ans[i].x,ans[i].y,ans[i].z);
            }

            puts(
".");
        }
    
    }

    
return 0;
}


Poj 3131

/*
    如图所示,问从初始状态变化到目标状态,不超过步
    规模比较大
    状态总数为:*6^8   1个为E,其余格子每个种可能
    我这里用了enum,这样编码会直观点吧
    用二进制编码,每三位bit代表一个格子

    状态很多,要用双向BFS,优先选择队列长度小的扩展,否则会超时
    还有注意判重时,用了Hash,节点要用静态数组!!!
    之前每次都make_pair()就超时了!!!
    map判重也超时了
*/


enum  Board  {RBW, BRW, RWB, WRB, BWR, WBR, E} ; // 0,1,
const   int  MAXN  =   500007 ;

struct  Node {
    
int pos;
    
short val;
    Node 
*next;
}
;
Node nodes[MAXN
* 20 ] ,  * pN;

struct  Hash {

    Node
* hash[MAXN];
    vector
<int> vt;

    
void init(){
        
for(vector<int>::iterator it = vt.begin() ; it != vt.end() ; it++){
            hash[
*it] = NULL;
        }

        vt.clear();
    }

    
void add(int pos , short val){
        
int mod = pos % MAXN;
        
if(hash[mod] == NULL){
            vt.push_back(mod);
        }

        pN
->pos = pos;
        pN
->val = val;
        pN
->next = hash[mod];
        hash[mod] 
= pN++;
        
//assert(pN < nodes + MAXN*20);
    }

    
short find(int pos){
        
int loc = pos % MAXN;
        Node 
*= hash[loc];
        
while(p != NULL ){
            
if(p->pos == pos){
                
return p->val;
            }

            p 
= p->next;
        }

        
return -1;
    }

}
;

Hash bfs , rbfs;

int  bin[ 10 ];
int  dx[]  =   {1,0,-1,0} ;
int  dy[]  =   {0,1,0,-1} ;
Board change[
6 ][ 4 =   {
    
{RWB, WBR, RWB, WBR},
    
{BWR, WRB, BWR, WRB},
    
{RBW, BWR, RBW, BWR},
    
{WBR, BRW, WBR, BRW},
    
{BRW, RWB, BRW, RWB},
    
{WRB, RBW, WRB, RBW}
}
;

#define  iset(val,pos,x)  (val ^=  val & bin[pos] , val |= x << 3*(pos) )
#define  get(val,pos)  ((val >> 3*(pos) ) & 7)

inline 
bool   out ( int  x ,  int  y) {
    
return x < 0 || x >= 3 || y < 0 || y >= 3;
}


void  gao(vector < int >   & from , vector < int >   & to , Hash  & hash) {
    to.clear();
    
for(vector<int>::iterator it = from.begin() ;  it != from.end() ; it++){
        
int &board = *it;
        
int pos , x , y , step = hash.find(board);
        
for(int i = 0 ;i  < 9 ;  i++){
            
if(get(board,i) == E){
                pos 
= i;
                y 
= i / 3;
                x 
= i % 3;
                
break;
            }

        }

        
for(int k = 0 ; k < 4 ; k ++){
            
int xx = x + dx[k];
            
int yy = y + dy[k];
            
if(out(xx,yy)){
                
continue;
            }

            
int next = board;
            
int nextPos = yy * 3 + xx , val = get(next, nextPos);
            iset(next,pos,change[val][k]);
            iset(next,nextPos,E);
            
if(hash.find(next) == -1){
                hash.add(next,step
+1);
                to.push_back(next);
            }

        }

    }

}

int  bibfs( int   & start ,  int  dest[ 2 ]) {

    vector
<int> Q[2] , rQ[2];
    
int cur = 0 , rcur = 0;

    pN 
= nodes;
    bfs.init();
    rbfs.init();

    bfs.add(start,
0);
    Q[cur].push_back(start);

    
int pos = 0;
    
while(get(dest[0], pos) != E){
        pos
++;
    }


    
for(int mask = 0 ; mask < (1<<9) ; mask++){        
        
if((mask>>pos) & 1){
            
continue;
        }

        
int next = 0;//init 0 !!!
        for(int i = 0 ;i < 9 ; i ++){
            iset(next, i, 
get(dest[(mask>>i)&1], i) );
        }

        
if(next == start){
            
return 0;
        }

        rbfs.add(next,
0);
        rQ[rcur].push_back(next);
    }


    
for(int step = 1 ; step <= 30 ; step++){
        
if(Q[cur].size() <= rQ[rcur].size()){//
            gao(Q[cur],Q[cur^1],bfs);
            cur 
^= 1;
            
for(vector<int>::iterator it = Q[cur].begin() ; it != Q[cur].end() ; it++){
                
if(rbfs.find(*it) != -1){
                    
return step;
                }

            }

        }
else{
            gao(rQ[rcur],rQ[rcur
^1],rbfs);
            rcur 
^= 1;
            
for(vector<int>::iterator it = rQ[rcur].begin() ; it != rQ[rcur].end() ; it++){
                
if(bfs.find(*it) != -1){
                    
return step;
                }

            }

        }

    }

    
return -1;
}
 

int  main()
{
    
//freopen("in","r",stdin);
    
//freopen("out","w",stdout);
    bin[0= 7;
    
for(int pos = 1 ; pos < 9 ; pos++){
        bin[pos] 
= bin[pos-1]<<3;
    }

    
for(int x,y;scanf("%d%d",&x,&y) , x != 0;){
        x
--;
        y
--;
        
int dest[2] , start = 0;
        
for(int i = 0; i < 3 ; i ++){
            
for(int j = 0 ; j < 3 ; j++){
                
char ch;
                scanf(
" %c",&ch);
                
if(ch == 'W'){
                    iset(dest[
0],3*i+j,RBW);
                    iset(dest[
1],3*i+j,BRW);
                }
else if(ch == 'B'){
                    iset(dest[
0],3*i+j,RWB);
                    iset(dest[
1],3*i+j,WRB);
                }
else if(ch == 'R'){
                    iset(dest[
0],3*i+j,BWR);
                    iset(dest[
1],3*i+j,WBR);
                }
else{
                    iset(dest[
0],3*i+j,E);
                    iset(dest[
1],3*i+j,E);
                }

            }

        }

        iset(start, 
3*y+x, E);
        cout
<<bibfs(start , dest)<<endl;
    }

    
return 0;
}


<think>我们正在讨论双向BFS算法。根据引用[5],双向BFS是一种优化策略,用于减少在搜索空间较大时的计算量。它的核心思想是从起点和终点同时开始进行BFS,当两个方向的搜索相遇时,路径就被找到了。这样可以显著减少搜索的节点数量,因为单向BFS的扩展是指数级的,而双向BFS可以将指数级减少为两个指数级之和。双向BFS的实现原理:1.同时从起点和终点开始进行BFS,使用两个队列分别存储两个方向的当前层节点。2.使用两个哈希表(或数组)分别记录从起点到达的节点和从终点到达的节点,同时记录步数(或者距离)。3.在每一步中,选择当前队列中节点数较少的方向进行扩展(平衡两个方向的扩展,以优化性能)。4.当从起点扩展的节点出现在终点的已访问集合中(或者反之)时,说明两个方向相遇,此时将两个方向的距离相加即可得到最短路径。双向BFS的应用场景:-通常用于求解最短路径问题,尤其是当搜索空间很大(如状态空间搜索)时,使用双向BFS可以大大减少搜索的节点数。-例如,在迷宫问题、拼图问题(如八数码)、单词接龙、解开密码锁等问题中,当状态空间很大时,双向BFS可以显著提高效率。实现示例(以解开密码锁问题为例,参考引用[5]):问题描述:有一个带有四个圆形拨轮的密码锁,每个拨轮有0到9共10个数字。初始状态为"0000",每次可以向上或向下旋转一个拨轮(即一个数字加1或减1,注意0的下一个数字是9,9的上一个数字是0)。同时,有一个死亡数字列表,如果拨轮转到了死亡数字上,则锁被锁定无法再旋转。给定目标数字,要求避开死亡数字,找到从"0000"转到目标数字的最少旋转次数。使用双向BFS的实现步骤:1.初始化两个队列:`q1`从起点"0000"开始,`q2`从目标`target`开始。2.初始化两个访问记录哈希表:`visited1`记录从起点访问过的节点和步数,`visited2`记录从终点访问过的节点和步数。将起点加入`visited1`(步数为0),终点加入`visited2`(步数为0)。3.当两个队列都不为空时,循环:a.选择当前节点数较少的队列进行扩展(假设为`q1`)。b.对`q1`的当前层的每个节点,生成相邻节点(每个拨轮向上或向下转,共8种可能)。c.如果生成的相邻节点在`visited2`中已经存在,则相遇,返回当前节点在`visited1`中的步数+1(加上相邻节点在`visited2`中的步数)。d.如果相邻节点是死亡数字,则跳过。e.如果相邻节点未在`visited1`中出现,则将其加入`visited1`(步数为当前步数+1)并加入`q1`。4.如果相遇则返回总步数,否则如果其中一个队列为空还未相遇,则无解。注意:为了避免重复扩展,我们每次只扩展一个方向的一层(或者一个节点),但通常为了简单,可以扩展一层(即当前队列中的所有节点)。另外,每次扩展后检查相遇。下面是一个使用双向BFS解决该问题的Python代码示例:```pythondefopenLock(deadends,target):iftarget=="0000":return0dead=set(deadends)if"0000"indead:return-1#生成相邻节点defget_neighbors(node):neighbors=[]foriinrange(4):num=int(node[i])#向上旋转up=(num+1)%10#向下旋转down=(num-1)%10ifdown<0:down+=10#注意:这里也可以统一用模10,但是向下旋转时,-1模10等于9,所以可以简写为(num-1)%10,但为了清晰,分开写forxin[up,down]:neighbor=node[:i]+str(x)+node[i+1:]neighbors.append(neighbor)returnneighbors#初始化双向BFSq1=deque(["0000"])q2=deque([target])visited1={"0000":0}#记录从起点到该节点的步数visited2={target:0}#记录从终点到该节点的步数whileq1andq2:#总是从节点数少的队列开始扩展iflen(q1)>len(q2):q1,q2=q2,q1visited1,visited2=visited2,visited1#扩展当前队列q1的一层size=len(q1)for_inrange(size):node=q1.popleft()#如果当前节点在另一个方向已经访问过,则相遇ifnodeinvisited2:returnvisited1[node]+visited2[node]forneighboringet_neighbors(node):ifneighborindeadorneighborinvisited1:continuevisited1[neighbor]=visited1[node]+1q1.append(neighbor)#交换后,下一轮扩展另一个方向(但这里通过交换队列和哈希表,使得下一轮扩展原来的q2,即现在的q1)return-1```注意:上述代码中,我们每次交换队列和哈希表,使得总是扩展较小的队列。这样在每一步中,我们扩展的都是当前节点数较少的方向,从而平衡两个方向的搜索。性能分析:双向BFS的时间复杂度最坏情况下是单向BFS的平方根,因为两个方向同时搜索,减少了搜索的层数。空间复杂度同样也会减少。相关问题:1.双向BFS在哪些情况下不适用?2.双向BFS如何避免在两个方向中重复扩展相同的节点?3.双向BFS和A*算法在性能上有何异同?</think>### 双向BFS算法原理及实现示例 #### 算法原理 双向BFS(Bidirectional BFS)是广度优先搜索的优化变体,核心思想是**从起点和终点同时进行BFS搜索**,当两个方向的搜索相遇时即找到最短路径。相比传统BFS,其优势在于: 1. **时间复杂度优化** 传统BFS时间复杂度为$O(b^d)$($b$为分支因子,$d$为目标深度)。双向BFS时间复杂度降为$O(b^{d/2} + b^{d/2})$,指数级减少搜索空间[^3][^5]。 2. **空间复杂度优化** 双向BFS通过两个较小队列替代单一的大队列,空间复杂度从$O(b^d)$降至$O(b^{d/2})$[^3]。 3. **终止条件** 当两个搜索方向的已访问集合出现交集时(即某个节点被双向访问),算法终止并拼接路径。 #### 实现示例(密码锁问题) **问题描述**: 一个4位密码锁(每位0-9),初始状态"0000",目标状态"0202"。禁止状态(deadends)为["0201","0101","0102","1212","2002"]。每次操作可旋转一个拨轮(±1),求最少操作步数[^5]。 **Python实现**: ```python from collections import deque def openLock(deadends, target): dead = set(deadends) if "0000" in dead: return -1 # 起点为死锁 # 双向BFS初始化 q_start = deque(["0000"]) q_target = deque([target]) visited_start = {"0000": 0} # 状态:步数 visited_target = {target: 0} # 生成相邻状态 def get_neighbors(node): neighbors = [] for i in range(4): num = int(node[i]) for dx in (1, -1): # 正反旋转 nx = (num + dx) % 10 # 处理0-9循环 neighbors.append(node[:i] + str(nx) + node[i+1:]) return neighbors while q_start and q_target: # 选择较小队列扩展(优化空间) if len(q_start) > len(q_target): q_start, q_target = q_target, q_start visited_start, visited_target = visited_target, visited_start size = len(q_start) for _ in range(size): node = q_start.popleft() # 相遇检测 if node in visited_target: return visited_start[node] + visited_target[node] # 跳过死锁 if node in dead: continue # 扩展新状态 for neighbor in get_neighbors(node): if neighbor not in visited_start: visited_start[neighbor] = visited_start[node] + 1 q_start.append(neighbor) return -1 # 无解 # 测试 deadends = ["0201","0101","0102","1212","2002"] target = "0202" print(openLock(deadends, target)) # 输出: 6 ``` #### 关键实现细节 1. **双向队列平衡** 每次选择节点数较少的队列扩展(`len(q_start) > len(q_target)`),避免单向过度增长[^5]。 2. **状态扩展函数** `get_neighbors`生成8个相邻状态(4个拨轮×±1旋转),通过取模`%10`处理0→9和9→0的循环。 3. **相遇判定** 当`node in visited_target`成立时,路径长度为`visited_start[node] + visited_target[node]`。 4. **死锁处理** 遇到`deadends`中的状态直接跳过,不加入队列。 #### 性能对比 | 算法 | 搜索方向 | 时间复杂度 | 空间复杂度 | |------------|----------|----------------|----------------| | 传统BFS | 单向 | $O(b^d)$ | $O(b^d)$ | | 双向BFS | 双向 | $O(b^{d/2})$ | $O(b^{d/2})$ | 此优化在状态空间较大时效果显著,如八数码问题、单词接龙、社交网络六度空间等场景[^3][^5]。 --- ### 相关问题 1. 双向BFS在哪些场景下比A*算法更适用? 2. 如何处理双向BFS中两个方向搜索速度不一致的问题? 3. 双向BFS能否应用于带权图的最短路径搜索?如何改造? 4. 双向BFS的相遇条件能否优化为路径成本之和最小化? 5. 如何证明双向BFS找到的路径一定是最短路径? [^1]: 广度优先搜索BFS)详解:原理、应用与实现 [^2]: 【图计算算法】广度优先搜索BFS)算法 [^3]: 专业学习|BFS算法介绍以及实现框架 [^5]: 广度优先搜索BFS优化,双向BFS
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值