BOJ[14226] - 이모티콘 by JavaScript
이모티콘
문제
언어
- JavaScript
순서도
- BFS 탐색
문제 풀이 step 1
- 영선이는 3 가지 연산을 이용해서 이모티콘의 개수를 늘릴 수 있는데, 이 때 이모티콘 S 개를 만들기 위해 필요한 시간의 최솟값을 출력해야 합니다.
- 결론부터 말씀드리면, BFS 탐색을 이용해서 풀 수 있습니다.
- 우선 그래프를 1 차원 배열의 형태로 풀 수 없습니다. 왜냐하면 모든 노드마다 클립보드에 복사된 이모티콘의 개수마다 다른 노드로 볼 수 있기 때문입니다.
- 그래서 그래프의 한 노드는 아래와 같은 형태를 지니고 있습니다.
node[count][clipboard]- “이모티콘의 개수가 count개 이며, 클립보드에 복사된 이모티콘의 개수는 clipboard 개 인 노드” 를 의미합니다.
- 그럼 이렇게 2 차원의 형태로 풀 수 있는지 검증을 해봐야겠습니다.
- 주어지는 범위가 1000 이하이므로
1000 * 1000 = 1000000으로 충분히 가능한 범위입니다.
- 그래서 그래프의 형태는 이모티콘의 개수와 클립보드에 복사된 개수 이 두 가지로 조합된 2 차원 배열 형태를 가지게됩니다.
문제 풀이 step 2
- 다음으로 BFS 탐색의 과정을 알아보겠습니다.
- 이 문제에서 다음 노드로 탐색하는 방법은 3 가지 있습니다.
- 화면에 있는 이모티콘을 모두 복사해서 클립보드에 저장
arr[from.count][from.count]
- 클립보드에 있는 모든 이모티콘을 화면에 붙여넣기
arr[from.count + from.clipboard][from.clipboard]
- 화면에 잇는 이모티콘 중 하나를 삭제
arr[from.count - 1][from.clipboard]
- 화면에 있는 이모티콘을 모두 복사해서 클립보드에 저장
- 그리고 각 노드에 시간을 기록하는 방식으로 방문 처리를 대신했습니다.
arr[from.count][from.count] = arr[from.count][from.clipboard] + 1;
- 그리고 클립보드에 복사된 개수가 몇 개이건 상관없이 이모티콘의 개수가 S 개인 노드가 하나라도 생기면 더이상의 탐색은 무의미합니다.
if (from.count === s) return arr[from.count][from.clipboard];- 모든 BFS 탐색을 끝내고, 나중에 이모티콘의 개수가 S 개인 모든 값들 중 최솟값을 찾는 과정으로 풀어야 할 것 같은데, 이렇게 해도 풀 수 있는 이유는 제가 생각하기에는 BFS 탐색의 시작점이 하나이기 때문이라고 생각합니다. (시작이 여러개의 반대)
- 그리고 시작점이 하나이기 때문에 이후로 탐색되는 이모티콘의 개수가 S 개인 노드는 처음 탐색된 값보다 같거나 그 이상의 값일 것입니다.
후기
- 꼭 다시 풀어볼 문제입니다.
- 이 문제의 가장 중요한 것은 1 차원 배열의 형태를 쥐어줬는데 그것을 2 차원의 형태로 바꿀 수 있느냐 없느냐 라고 생각합니다.
- 그리고 변수 명을 좀더 간결하게 축소화하는 것이 맞을까 라는 의문이 많이 들었습니다.
- 의미를 명확하게 주고 싶어서 변수명을 정직하게 줄이지 않고 사용을 했는데, 오히려 코드를 작성하는 것도 어렵고 가독성도 떨어지는 것 같습니다.
- 하지만 의미를 모호하게 주는 것보다는 낫다고 생각하지만, 해결점을 찾아야할 것 같습니다. (의미를 최대한 살리면서 줄여보는 방식으로)
소스 코드 1
const input = require("fs").readFileSync("/dev/stdin").toString().split("\n");
class Dot {
constructor(count, clipboard) {
this.count = count;
this.clipboard = clipboard;
}
}
class Queue {
constructor() {
this.bucket = [];
this.front = -1;
this.rear = -1;
}
isEmpty() {
return this.front === this.rear;
}
enqueue(data) {
this.bucket[++this.front] = data;
}
dequeue() {
if (!this.isEmpty()) return this.bucket[++this.rear];
}
}
const BFS = (arr, s) => {
const queue = new Queue();
// 초기 이모티콘 1 개
arr[1][0] = 0;
queue.enqueue(new Dot(1, 0));
while (!queue.isEmpty()) {
const from = queue.dequeue();
// 찾으면 더이상의 탐색은 의미없음 그래서 바로 return
if (from.count === s) return arr[from.count][from.clipboard];
// 1. 화면에 있는 이모티콘을 모두 복사해서 클립보드에 저장
if (arr[from.count][from.count] === undefined) {
arr[from.count][from.count] = arr[from.count][from.clipboard] + 1;
queue.enqueue(new Dot(from.count, from.count));
}
// 2. 클립보드에 있는 모든 이모티콘을 화면에 붙여넣기
if (
from.count + from.clipboard <= s &&
arr[from.count + from.clipboard][from.clipboard] === undefined
) {
arr[from.count + from.clipboard][from.clipboard] =
arr[from.count][from.clipboard] + 1;
queue.enqueue(new Dot(from.count + from.clipboard, from.clipboard));
}
// 3. 화면에 있는 이모티콘 중 하나를 삭제
if (
0 <= from.count - 1 &&
arr[from.count - 1][from.clipboard] === undefined
) {
arr[from.count - 1][from.clipboard] = arr[from.count][from.clipboard] + 1;
queue.enqueue(new Dot(from.count - 1, from.clipboard));
}
}
};
const solution = (input) => {
const s = parseInt(input[0]);
const arr = Array.from({length: s + 1}, () => []);
const min = BFS(arr, s);
return min;
};
console.log(solution(input));