双向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;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值