View
유형: 그래프, BFS
문제: https://www.acmicpc.net/problem/7562
7562번: 나이트의 이동
체스판 위에 한 나이트가 놓여져 있다. 나이트가 한 번에 이동할 수 있는 칸은 아래 그림에 나와있다. 나이트가 이동하려고 하는 칸이 주어진다. 나이트는 몇 번 움직이면 이 칸으로 이동할 수
www.acmicpc.net
풀이 1
처음 생각해낸 풀이. 큐에 좌표뿐만 아니라 카운트 수도 저장했다.
초기 코드는 메모리 초과로 실패했는데, 방문처리를 큐에서 pop할 때가 아니라 파생위치를 큐에 넣을 때 해줘야한다.
왜냐하면, 큐에서 pop할 때 방문처리를 하면 큐에 있는 원소들은 전부 방문하지 않았다는 전제가 깔린다.
따라서 큐에 좌표가 중복으로 들어갈 수도 있어서, 불필요한 탐색이 많아진다. (그래서 메모리 초과가 발생함)
#include "iostream"
#include "vector"
#include "queue"
using namespace std;
int solution(int len, vector<int> start, vector<int> end){
int answer = 0;
// 나이트가 이동 가능한 방향
int xPos[] = {-2, -2, -1, -1, 1, 1, 2, 2};
int yPos[] = {1, -1, 2, -2, 2, -2, 1, -1};
// 맵 구성
vector<vector<bool>> maps(len);
for(auto &now: maps) {
for(int i = 0; i < len; i++) now.push_back(false);
}
// 큐 구성
queue<vector<int>> q;
q.push({start[0], start[1], 0}); // 시작점 추가
maps[start[0]][start[1]] = true;
while(!q.empty()){
// 큐의 맨 앞의 원소를 pop
auto now = q.front(); q.pop();
auto x = now[0], y = now[1], cnt = now[2];
// 정답에 도달했다면 탈출
if(x == end[0] && y == end[1]) {
answer = cnt;
break;
}
// 파생 위치를 큐에 넣기
for(int i = 0; i < 8; i++){
auto tempX = x + xPos[i];
auto tempY = y + yPos[i];
// 범위 초과된건 넘어감
if (tempX < 0 || tempX >= len || tempY < 0 || tempY >= len) continue;
else if(!maps[tempX][tempY]){
// 파생중에 방문하지 않은건 큐에 넣음
q.push({tempX, tempY, cnt+1});
maps[tempX][tempY] = true;
}
}
}
return answer;
}
int main(){
ios::sync_with_stdio(0);
int n; cin >> n;
while (n--){
int len; cin >> len;
vector<int> st(2); cin >> st[0] >> st[1];
vector<int> ed(2); cin >> ed[0] >> ed[1];
cout << solution(len, st, ed) << endl;
}
return 0;
}
풀이 2
여기서는 큐에 카운트 횟수를 넣지 않고, maps에 카운트 횟수를 저장한다.
이렇게 하면 maps 좌표에 해당하는 값이 0일 때에만 방문하지 않은 노드로 인식된다.
풀이 1번의 방문처리를 왜 파생을 계산하는 시점에서 해야하는지 조금 더 이해하기 쉽다.
#include "iostream"
#include "vector"
#include "queue"
using namespace std;
int solution(int len, vector<int> start, vector<int> end){
// 나이트가 이동 가능한 방향
int xPos[] = {-2, -2, -1, -1, 1, 1, 2, 2};
int yPos[] = {1, -1, 2, -2, 2, -2, 1, -1};
// 맵 구성
vector<vector<int>> maps(len);
for(auto &now: maps) {
for(int i = 0; i < len; i++) now.push_back(0);
}
// 큐 구성
queue<vector<int>> q;
q.push({start[0], start[1]}); // 시작점 추가
while(!q.empty()){
// 큐의 맨 앞의 원소를 pop
auto now = q.front(); q.pop();
auto x = now[0], y = now[1];
// 정답에 도달했다면 탈출
if(x == end[0] && y == end[1]) break;
// 파생 위치를 큐에 넣기
for(int i = 0; i < 8; i++){
auto tempX = x + xPos[i];
auto tempY = y + yPos[i];
// 범위 초과된건 넘어감
if (tempX < 0 || tempX >= len || tempY < 0 || tempY >= len) continue;
// 파생중에 방문하지 않은건 큐에 넣음 (값이 0일때만 유효함)
else if(!maps[tempX][tempY]){
q.push({tempX, tempY});
maps[tempX][tempY] = maps[x][y] + 1;
// 파생중에 정답이 있다면 탈출
if(tempX == end[0] && tempY == end[1]) break;
}
} // 파생 넣기 끝
}
return maps[end[0]][end[1]];
}
int main(){
ios::sync_with_stdio(0);
int n; cin >> n;
while (n--){
int len; cin >> len;
vector<int> st(2); cin >> st[0] >> st[1];
vector<int> ed(2); cin >> ed[0] >> ed[1];
cout << solution(len, st, ed) << endl;
}
return 0;
}
'백준 알고리즘' 카테고리의 다른 글
백준 9237번 - 이장님 초대 (C++) (0) | 2021.09.20 |
---|---|
백준 14916번 - 거스름돈 (C++) (0) | 2021.09.19 |
백준 14397번 - 해변 (C++) (0) | 2021.09.18 |
백준 6550번 - 부분 문자열 (C++) (0) | 2021.09.18 |
백준 2891번 - 카약과 강풍 (C++) (0) | 2021.09.18 |
reply