双向bfs

事实上 H D U − 2612 HDU - 2612 HDU2612也是双向 b f s bfs bfs,但由于题目要求的原因,所以没有将其优势发挥出来。
双向 b f s bfs bfs实质上是引入起点和终点,一起遍历,并且给数组多加一维,结束的标准时到达的这个点的另一维也已经到达了。
并且双向 b f s bfs bfs是双向的最短路,所以此时一定是最短路。考虑广度优先遍历,越到后面的层数,常数越大,如果采用双向 b f s bfs bfs可以使常数大大减小。

下面是一道例题: Uva1601
要求( n ≤ 3 n≤3 n3)个小写字母走到对应的大写字母位置,不能够直接交换位置,不能够走到障碍物。每一步可以有多个字母移动(相互独立),每 2 ∗ 2 2*2 22个方格都会有个障碍物,求最小步数。

这种图一般都是 b f s bfs bfs,考虑怎么维护状态,直接记录三个点的位置即可,状态数是 25 6 3 256^3 2563,一千多万。每次转移的代价是 5 3 5^3 53。显然不合理,所以预处理出所有位置能够到达的位置(因为障碍物特别多)。这样子可以大大减少时间,而且合法状态实际上没有那么多(有障碍物的也不合法。

这样子就可以通过了。但是使用双向 b f s bfs bfs几乎没有什么改动,却减少了一倍的时间。
同时需要注意的是:我们记录点的时候可以映射到一维数组里,这里同一个状态只由三个一维坐标决定。

这里是双向 b f s bfs bfs的代码:

#include<bits/stdc++.h>
#define FOR(i,a,b) for(int i=a;i<=b;i++)
#define ll long long
using namespace std;

vector<pair<int,int> >G[303];
pair<int,int>s[3],t[3];
int Map[303][33];
int vis[257][257][258][2];
int w,h,n;
map<ll,int>M;

struct node{
    int a=0,b=0,c=0,step,flag;
    node(){}
    node(int _a,int _b,int _c,int _step,int _flag):a(_a),b(_b),c(_c),step(_step),flag(_flag){}
};

int toone(pair<int,int> u){
    return (u.first-1)*w+u.second;
}

bool check(node u,node v){
    if(n==1)return true;
    if(n==2){
        if(v.a==v.b)return false;
        if(v.a==u.b&&v.b==u.a)return false;
        return true;
    }
    if(n==3){
        if(v.a==v.b||v.a==v.c||v.b==v.c)return false;
        if(v.a==u.b&&v.b==u.a)return false;
        if(v.b==u.c&&v.c==u.b)return false;
        if(v.a==u.c&&v.c==u.a)return false;
        return true;
    }
}

int bfs(){
    queue<node>q;
    memset(vis,0,sizeof(vis));
    q.push(node(toone(s[0]),toone(s[1]),toone(s[2]),1,0));
    q.push(node(toone(t[0]),toone(t[1]),toone(t[2]),1,1));
    while(!q.empty()){
        node u=q.front();q.pop();
        if(vis[u.a][u.b][u.c][u.flag])continue;
        vis[u.a][u.b][u.c][u.flag]=u.step;
       // cout<<"("<<(u.a+w-1)/w<<","<<u.a%w<<")";
       // cout<<"("<<(u.b+w-1)/w<<","<<u.b%w<<")";
       // cout<<"("<<(u.c+w-1)/w<<","<<u.c%w<<")";
       // cout<<u.flag<<endl;
        if(vis[u.a][u.b][u.c][u.flag^1]){
            return u.step+vis[u.a][u.b][u.c][u.flag^1]-2;
        }
        switch(n){
            case 1:
                for(int i=0;i<G[u.a].size();i++)if(!Map[G[u.a][i].first][G[u.a][i].second]){
                    q.push(node(toone(G[u.a][i]),0,0,u.step+1,u.flag));
                }
                break;
            case 2:
                if(n==2){
                    for(int i=0;i<G[u.a].size();i++)if(!Map[G[u.a][i].first][G[u.a][i].second]){
                        for(int j=0;j<G[u.b].size();j++)if(!Map[G[u.b][j].first][G[u.b][j].second]){
                            node tmp=node(toone(G[u.a][i]),toone(G[u.b][j]),0,u.step+1,u.flag);
                            if(check(u,tmp))q.push(tmp);
                        }
                    }
                }
                break;
            case 3:
                if(n==3){
                    for(int i=0;i<G[u.a].size();i++)if(!Map[G[u.a][i].first][G[u.a][i].second]){
                        for(int j=0;j<G[u.b].size();j++)if(!Map[G[u.b][j].first][G[u.b][j].second])
                            for(int k=0;k<G[u.c].size();k++)if(!Map[G[u.c][k].first][G[u.c][k].second]){
                            node tmp=node(toone(G[u.a][i]),toone(G[u.b][j]),toone(G[u.c][k]),u.step+1,u.flag);
                            if(check(u,tmp))q.push(tmp);
                        }
                    }
                }
                break;
        }
    }
}

int main(){
    while(~scanf("%d%d%d",&w,&h,&n)){
        if(w==0&&h==0&&n==0)break;
        getchar();char ch;
        t[0]=s[0]={1,0};
        t[1]=s[1]={1,0};
        t[2]=s[2]={1,0};
        for(int i=1;i<=h;i++){
            for(int j=1;j<=w;j++){
                ch=getchar();
                if(ch=='#')Map[i][j]=1;
                else Map[i][j]=0;
                if(ch=='a')s[0].first=i,s[0].second=j;
                if(ch=='b')s[1].first=i,s[1].second=j;
                if(ch=='c')s[2].first=i,s[2].second=j;
                if(ch=='A')t[0].first=i,t[0].second=j;
                if(ch=='B')t[1].first=i,t[1].second=j;
                if(ch=='C')t[2].first=i,t[2].second=j;
                G[(i-1)*w+j].clear();
            }
            getchar();
        }
        //cout<<t[0].first<<" "<<t[0].second<<endl;
        for(int i=1;i<=h;i++){
            for(int j=1;j<=w;j++)if(!Map[i][j]){
                if(i-1>=1&&!Map[i-1][j])G[(i-1)*w+j].push_back(make_pair(i-1,j));
                if(i+1<=h&&!Map[i+1][j])G[(i-1)*w+j].push_back(make_pair(i+1,j));
                if(j-1>=1&&!Map[i][j-1])G[(i-1)*w+j].push_back(make_pair(i,j-1));
                if(j+1<=w&&!Map[i][j+1])G[(i-1)*w+j].push_back(make_pair(i,j+1));
                G[(i-1)*w+j].push_back(make_pair(i,j));
            }
            //puts("");
        }
        cout<<bfs()<<endl;
    }
}
### 双向BFS算法的Python实现 双向广度优先搜索(Bidirectional BFS)是一种优化的图遍历方法,它通过从起点和终点同时扩展来减少搜索空间。这种方法特别适用于寻找最短路径的问题。 以下是基于队列数据结构的一个标准双向BFS Python实现: ```python from collections import deque def is_goal_reached(node_a, node_b): """判断两个节点是否相同""" return node_a == node_b def get_neighbors(node): """获取当前节点的所有邻居节点""" # 这里假设有一个函数可以返回给定节点的所有相邻节点 neighbors = [] # 替换为实际逻辑 return neighbors def bidirectional_bfs(start_node, end_node): """双向BFS算法""" if start_node == end_node: return [start_node] # 初始化前向和反向的队列以及访问集合 forward_queue = deque([start_node]) forward_visited = {start_node} backward_queue = deque([end_node]) backward_visited = {end_node} intersect_node = None while forward_queue and backward_queue: # 前向扩展 current_forward = forward_queue.popleft() for neighbor in get_neighbors(current_forward): if neighbor not in forward_visited: forward_visited.add(neighbor) forward_queue.append(neighbor) # 检查是否有交集 if neighbor in backward_visited: intersect_node = neighbor break if intersect_node: break # 后向扩展 current_backward = backward_queue.popleft() for neighbor in get_neighbors(current_backward): if neighbor not in backward_visited: backward_visited.add(neighbor) backward_queue.append(neighbor) # 检查是否有交集 if neighbor in forward_visited: intersect_node = neighbor break if intersect_node: break if intersect_node: path_from_start_to_intersect = reconstruct_path(start_node, intersect_node, forward_visited)[^4] path_from_end_to_intersect = reconstruct_path(end_node, intersect_node, backward_visited)[^4] return list(reversed(path_from_end_to_intersect))[:-1] + path_from_start_to_intersect else: return [] def reconstruct_path(start_node, target_node, visited_set): """重建路径""" path = [] current = target_node while current != start_node: path.append(current) # 需要记录父节点以便回溯路径 (这里省略具体实现细节) current = parent_map[current][^5] path.append(start_node) return list(reversed(path)) ``` 上述代码展示了如何利用双端队列`deque`分别从前向和后向进行扩展,并在两者相遇时停止搜索。此过程显著减少了传统单向BFS所需的计算量[^6]。 #### 关键点说明 - **is_goal_reached**: 判断目标是否达到。 - **get_neighbors**: 获取某个节点的所有邻接节点。 - **bidirectional_bfs**: 主体部分实现了双向BFS的核心逻辑。 - **reconstruct_path**: 负责根据已有的访问信息重构完整的路径。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值