[Baekjoon]206号破壁後移動cpp
[白俊]2667号団地番号問題リンク
この問題はbfsで解決した.パスに重みを設定する最短パス検索は、dfsを使用して解くのが望ましいが、重みのない最短パスはbfsを使用して解くべきである.一定の経路を経て、初めて特定のセルに到達した場合、経路の長さが最小になることは保証されないからです.
この問題は一般的なbfs問題とあまり変わらないように見えますが、「必要であれば壁を除去できる」という条件が含まれています.これは論理に大きな影響を及ぼす.
つまり.壁を壊さずに移動するアクセス情報 壁破壊状態に移動したアクセス情報 共同で管理しなければならない.始点から終点まで、終点ではなくある点に到達し、移動経路の長さが移動経路の長さと同じであれば、破壊しないほうがいい(壁を取り外して破壊し、破壊が非常に混乱している).これは、進む道に「破らなければならない」壁がある可能性があるからです.
したがって、破壁移動の距離が非破壁移動の距離と等しい場合、当然、非破壁移動の方法が選択される.あるいは、壁を壊すと距離がずいぶん短くなりますが、壁を壊さずに迂回すれば、もっと長い時間で着くことができ、この経路も意味のある経路になります.
このため、「壁を破壊せずに移動するアクセス情報」と「壁を破壊した場合に移動するアクセス情報」とが一緒に管理される.
bfsを用いて、ルックアップアルゴリズムにおける「この点が可動点であるかどうか」、「その点にアクセスしたレコードがあるかどうか」を判断し、両方の条件が満たされた場合、次のアクセスポイントに追加する.これをcppコードとして記述すると、以下のように表すことができる.次の場所は「道」で訪問したことがない 次の場所は「壁」で、壁を壊したことはありません. 次の場所が壁の場合、その場所を訪問したことがなくても、壁を壊した記録があればどうせ行けないので、訪問の有無を確認する必要はありません.以降の内容では、壁を破壊するか否かを次の場所は「道」で訪問したことがない
変更しない 次の場所は「壁」で、壁を壊したことはありません. 上記の場合、
これらのコンテンツを整理して生成される完全なソースコードは、次のとおりです.
この問題はbfsで解決した.パスに重みを設定する最短パス検索は、dfsを使用して解くのが望ましいが、重みのない最短パスはbfsを使用して解くべきである.一定の経路を経て、初めて特定のセルに到達した場合、経路の長さが最小になることは保証されないからです.
・主なアイデア
この問題は一般的なbfs問題とあまり変わらないように見えますが、「必要であれば壁を除去できる」という条件が含まれています.これは論理に大きな影響を及ぼす.
つまり.
したがって、破壁移動の距離が非破壁移動の距離と等しい場合、当然、非破壁移動の方法が選択される.あるいは、壁を壊すと距離がずいぶん短くなりますが、壁を壊さずに迂回すれば、もっと長い時間で着くことができ、この経路も意味のある経路になります.
このため、「壁を破壊せずに移動するアクセス情報」と「壁を破壊した場合に移動するアクセス情報」とが一緒に管理される.
・アルゴリズム
bfsを用いて、ルックアップアルゴリズムにおける「この点が可動点であるかどうか」、「その点にアクセスしたレコードがあるかどうか」を判断し、両方の条件が満たされた場合、次のアクセスポイントに追加する.これをcppコードとして記述すると、以下のように表すことができる.
if(!map[nextY][nextX] && !visit[nextY][nextX]) { ... } // map 변수는 길이 1, 벽이 0
「しかし、今回の問題は状況が違う」「壁を破壊したかどうか」の情報に基づいて、特定の場所にアクセスできるからです.この問題では、次の場所に回るために確認が必要な場合は2つに分けられます.breaking
という変数で表現する.また、上記条件を満たす場合、次の場所に移動するには、以下の処理が必要となる.変更しない
breaking
の場合、次のポイントをキューに入れます.breaking
をtrueにし、次のポイントをキューに入れます.breaking
falseからtrueに変更できますが、trueからfalseに変更することはできません.つまり、壁を打ち砕かずに破砕した状態にすることはできるが、破砕した事実を隠すことはできない.これらのコンテンツを整理して生成される完全なソースコードは、次のとおりです.
#include <iostream>
#include <queue>
#include <vector>
struct state{
int x;
int y;
int breaking;
};
std::pair<int, int> direction[4] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
int rowSize, colSize;
int map[1000][1000];
int visit[1000][1000][2]; // 벽을 부수지 않은 상태 = 0, 벽을 부순 상태 = 1
std::queue<state> q;
int bfs(){
while(!q.empty()){
state cur = q.front();
q.pop();
if(cur.x == colSize - 1 && cur.y == rowSize - 1){ // 큐의 원소들을 따라 도착 지점에 도달한
return visit[cur.y][cur.x][cur.breaking]; // 첫 번째 경로가 최단 경로임이 보장되기 때문에
} // 도착 지점에 도달하자마자 bfs 중단
for(auto dir : direction){
int nextX = cur.x + dir.second;
int nextY = cur.y + dir.first;
if(nextX < 0 || nextX >= colSize || nextY < 0 || nextY >= rowSize){
continue;
}
if(map[nextY][nextX] == 1 && !cur.breaking){
q.push({nextX, nextY, 1});
visit[nextY][nextX][1] = visit[cur.y][cur.x][cur.breaking] + 1;
}
else if(map[nextY][nextX] == 0 && !visit[nextY][nextX][cur.breaking]){
q.push({nextX, nextY, cur.breaking});
visit[nextY][nextX][cur.breaking] = visit[cur.y][cur.x][cur.breaking] + 1;
}
}
}
return -1; // 도착 지점에 도달하지 못한 채로 bfs가 종료되면 -1을 반환
}
int main(){
scanf("%d %d", &rowSize, &colSize);
for(int row = 0; row < rowSize; row++){
std::string line;
std::cin >> line;
for(int index = 0; index < colSize; index++){
map[row][index] = line[index] - '0';
}
}
q.push({0, 0, 0});
visit[0][0][0] = 1;
printf("%d", bfs());
}
Reference
この問題について([Baekjoon]206号破壁後移動cpp), 我々は、より多くの情報をここで見つけました https://velog.io/@cedongne/Baekjoon-2206번-벽-부수고-이동하기.cppテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol