事实上
H
D
U
−
2612
HDU - 2612
HDU−2612也是双向
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
n≤3)个小写字母走到对应的大写字母位置,不能够直接交换位置,不能够走到障碍物。每一步可以有多个字母移动(相互独立),每
2
∗
2
2*2
2∗2个方格都会有个障碍物,求最小步数。
这种图一般都是 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;
}
}