[BOJ]206-破壁と移動
https://www.acmicpc.net/problem/2206
質問する
N×Mのマトリックス表現のマッピングがあります.地図では、0は移動可能な位置、1は移動不可能な壁の位置を示す.(1,1)から(N,M)の位置に移動し、最短経路に移動します.最短パスとは、地図上の最小セルを通るパスで、開始セルと終了セルが含まれます.
移動中に壁を割ったり移動したりする経路がもっと短い場合は、壁を割って移動することができます.
1つのセルで移動できるセルは上下左右に隣接するセルです.
地図を指定すると、最短パスを解くプログラムが作成されます.
入力
第1行はN(1≦N≦1000),M(1≦M≦1000)を与える.次のN行はMの数字で地図を与えます.(1,1)と(N,M)は常に0であると仮定する.
しゅつりょく
1行目に最短距離を出力します.不可能な場合は-1を出力します.
サンプルI/O
入力例1 例出力1 例2 例出力2
入力はstringでなければならないので、座標ごとにデータを入力する際にint型データを格納し、「0」を含まない.
1.壁を確認したらブロック(壁を割ったのか?)変数値は1ですか?
-この場合、壁を一度に砕くだけで済むと仮定します.
2.アクセスされていない0が見つかりました.
-既存のBFSと同様に行う.
これは,キューに座標情報を格納するだけでなく,壁を打ち砕くか否かの情報を格納して処理する方法である.そして全部で2つのvisitが並んでいます.
壁を壊したとき、壊さなかったとき.
この二つの状況が分割できるかどうかはこの問題の要求である.本当によく出てくるタイプなので、しっかり勉強すべきです.
質問する
N×Mのマトリックス表現のマッピングがあります.地図では、0は移動可能な位置、1は移動不可能な壁の位置を示す.(1,1)から(N,M)の位置に移動し、最短経路に移動します.最短パスとは、地図上の最小セルを通るパスで、開始セルと終了セルが含まれます.
移動中に壁を割ったり移動したりする経路がもっと短い場合は、壁を割って移動することができます.
1つのセルで移動できるセルは上下左右に隣接するセルです.
地図を指定すると、最短パスを解くプログラムが作成されます.
入力
第1行はN(1≦N≦1000),M(1≦M≦1000)を与える.次のN行はMの数字で地図を与えます.(1,1)と(N,M)は常に0であると仮定する.
しゅつりょく
1行目に最短距離を出力します.不可能な場合は-1を出力します.
サンプルI/O
入力
6 4
0100
1110
1000
0000
0111
0000
15
入力4 4
0111
1111
1111
1110
-1
Solution#include <iostream>
#include <deque>
#include <tuple>
#define MAX 1000
using namespace std;
int N, M;
int MATRIX[MAX][MAX];
int visit[MAX][MAX][2];
int dx[4] = {1, -1, 0, 0};
int dy[4] = {0, 0, 1, -1};
void BFS(){
deque<tuple<int, int, int>> Q;
Q.push_back({0, 0, 1});
visit[0][0][1] = 1;
while(!Q.empty()){
int X , Y, block;
tie(X, Y, block) = Q.front();
Q.pop_front();
if(X == N - 1 && Y == M - 1){
cout << visit[X][Y][block] << "\n";
return;
}
for(int i = 0; i < 4; i++){
int nx = X + dx[i];
int ny = Y + dy[i];
if(nx >= 0 && nx < N && ny >= 0 && ny < M){
if(MATRIX[nx][ny] == 1 && block == 1){
visit[nx][ny][block - 1] = visit[X][Y][block] + 1;
Q.push_back({nx, ny, block - 1});
}
if(MATRIX[nx][ny] == 0 && visit[nx][ny][block] == 0){
visit[nx][ny][block] = visit[X][Y][block] + 1;
Q.push_back({nx, ny, block});
}
}
}
}
cout << "-1\n";
return;
}
int main(){
cin >> N >> M;
for(int i = 0; i < N; i++){
string tmp; cin >> tmp;
for(int j = 0; j < M; j++) MATRIX[i][j] = tmp[j] - '0';
}
BFS();
}
BFSが適用されるかどうかの問題です.この問題はかなり難しい.入力はstringでなければならないので、座標ごとにデータを入力する際にint型データを格納し、「0」を含まない.
void BFS(){
deque<tuple<int, int, int>> Q;
Q.push_back({0, 0, 1});
visit[0][0][1] = 1;
while(!Q.empty()){
int X , Y, block;
tie(X, Y, block) = Q.front();
Q.pop_front();
if(X == N - 1 && Y == M - 1){
cout << visit[X][Y][block] << "\n";
return;
}
for(int i = 0; i < 4; i++){
int nx = X + dx[i];
int ny = Y + dy[i];
if(nx >= 0 && nx < N && ny >= 0 && ny < M){
if(MATRIX[nx][ny] == 1 && block == 1){
visit[nx][ny][block - 1] = visit[X][Y][block] + 1;
Q.push_back({nx, ny, block - 1});
}
if(MATRIX[nx][ny] == 0 && visit[nx][ny][block] == 0){
visit[nx][ny][block] = visit[X][Y][block] + 1;
Q.push_back({nx, ny, block});
}
}
}
}
cout << "-1\n";
return;
}
既存のBFSとは異なり2つのケースに分けられる.1.壁を確認したらブロック(壁を割ったのか?)変数値は1ですか?
-この場合、壁を一度に砕くだけで済むと仮定します.
2.アクセスされていない0が見つかりました.
-既存のBFSと同様に行う.
これは,キューに座標情報を格納するだけでなく,壁を打ち砕くか否かの情報を格納して処理する方法である.そして全部で2つのvisitが並んでいます.
壁を壊したとき、壊さなかったとき.
この二つの状況が分割できるかどうかはこの問題の要求である.本当によく出てくるタイプなので、しっかり勉強すべきです.
Reference
この問題について([BOJ]206-破壁と移動), 我々は、より多くの情報をここで見つけました https://velog.io/@sierra9707/BOJ-2206-벽-부수고-이동하기テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol