公式
E - 洞窟探検と地下水路 / Cave Exploration and Underground Waterways 解説
by
E - 洞窟探検と地下水路 / Cave Exploration and Underground Waterways 解説
by
physics0523
最短経路問題として解いても構いませんが、今回は別の解法を紹介します。
0-1 BFS と呼ばれる手法を応用します。
移動にかかる時間が \(0,1,2\) 分のいずれかであることを利用します。
\(0,1,2\) の番号が付いた配列を用意します。
その上で、以下を繰り返します。
- 最初は \(0\) 番の配列に始点のみを入れる。
- \(i=0,1,2,\dots\) について、以下を繰り返す。
- \(i \% 3\) 番の配列が空になるまで以下を繰り返す。
- 配列から要素を取り出し、そのマスから隣接したマスについての移動を考える。
- その移動が最短経路を更新するなら、移動にかかる時間を \(t\) として \((i+t) \% 3\) 番の配列に移動後のマスを入れる。
これで priority_queue にかかる \(\log\) を取り除くことができ、全体で時間計算量 \(O(HW)\) で動作します。
実装例 (C++):
#include<bits/stdc++.h>
using namespace std;
using pi=pair<int,int>;
int dx4[4]={-1,1,0,0};
int dy4[4]={0,0,-1,1};
int wei(char x,char y){
if(x=='V' && y=='V'){return 0;}
if(y=='V'){return 2;}
return 1;
}
int main(){
int H,W;
cin >> H >> W;
pi S,G;
vector<string> C(H);
for(int i=0;i<H;i++){
cin >> C[i];
for(int j=0;j<W;j++){
if(C[i][j]=='S'){S={i,j};}
if(C[i][j]=='G'){G={i,j};}
}
}
vector<vector<int>> fl(H,vector<int>(W,0));
vector<vector<int>> dist(H,vector<int>(W,1e9));
vector<vector<pi>> mem(3);
int sz=1;
dist[S.first][S.second]=0;
mem[0].push_back(S);
for(int d=0;sz>0;d++){
while(!mem[d%3].empty()){
auto od=mem[d%3].back();
mem[d%3].pop_back();
sz--;
if(od==G){
cout << d << "\n";
return 0;
}
if(fl[od.first][od.second]){continue;}
fl[od.first][od.second]=1;
for(int k=0;k<4;k++){
int nx=od.first+dx4[k];
int ny=od.second+dy4[k];
if(!(0<=nx && nx<H)){continue;}
if(!(0<=ny && ny<W)){continue;}
if(C[nx][ny]=='X'){continue;}
int len=wei(C[od.first][od.second],C[nx][ny]);
if(dist[nx][ny]>d+len){
dist[nx][ny]=d+len;
mem[dist[nx][ny]%3].push_back({nx,ny});
sz++;
}
}
}
}
cout << "NO\n";
return 0;
}
投稿日時:
最終更新:
