#12851. 숨바꼭질 2
Problem
Solution
- 방법의 수를 구하는 것이 추가가 되었다.
- 이는 DP를 활용하여 구한다.
- 방문하지 않은 경로라면 방법의 수는 그대로 유지
- 방문한 경우 + 거리 차이가 1인 경우에만 방법의 수+1
거리 차이가 1인 경우에만 최소비용을 만족하는 경로이기 때문이다.
1 Try
1 |
|
1 |
|
Goal: 최대 5번 이동해서 만들 수 있는 가장 큰 블록의 값 구하기
입력
N: ~20
0: 빈칸
2^i(i= 1, 2…10): 블록 // 적어도 하나 주어짐
1 | void dfs(int idx) { |
moveBlock()
블럭 이동움직이는 방향이 좌우면 한 행의 열이 바뀌면서 board위의 블럭들이 바뀐다.
이때 좌로 이동하면 오른쪽부터 탐색, 우로 이동하면 왼쪽부터 탐색해야 한다.
움직이는 방향이 상하일 때도 위와 같은 방식이다. 이를 잘 구분해주어 update할 때 행, 열의 인덱스를 반영한다.
update()
아래 코드는 좌우로 이동할 때 블럭들을 갱신하는 함수다.1 | void updateCol(int i, int j, queue<int> &zero) { |
1 |
|
위의 코드가 틀린 Test case
7
2 2 2 2 2 2 2
2 0 2 2 2 2 2
2 0 2 2 2 2 2
2 0 2 2 2 2 2
2 2 2 0 2 2 2
2 2 2 2 2 2 0
2 2 2 2 2 2 0
-> 32 // output
디버깅용 코드를 보면 알겠지만 방향을 3(오른쪽)으로 했을 때 board의 블럭들을 확인해보니
실제로 잘 합쳐지지 않았던 것이다. (solution에는 정답 코드를 반영)
1 |
|
1 |
|
굳이 이를 최소화시키는 방법을 생각하기보다 컴퓨터가 알아서 최소의 방법을 계산하도록 하자. → 하노이 탑도 알고리즘이 존재
보조 기둥 필요없이 바로 목표 기둥으로 이동하면 된다.1
2
3
4
5
6
7// recursive frame
void move(원반 개수, 시작, 보조, 목표) { }
if(원반의 개수 == 1) {
시작->목표
return;
}
원반의 개수가 1보다 클때는 어떻게 해야 할까?
가장 큰 원반을 제외한 모든 원반이 보조 기둥에 있어야 한다. → 이게 포인트
1
2// 맨 아래에 있는 원반을 제외한 모든 원반을 보조 기둥으로 옮긴다.
move(원반개수-1, 시작, 목표, 보조); // 시작 -> 보조
그러면 가장 큰 원반은 이 부분이 적용된다.1
2
3
4if(원반의 개수 == 1) {
시작->목표
return;
}
가장 큰 원반이 목표 기둥으로 이동하였고, 이제 이 원반은 없는 것으로 보아도 무방하다. 나머지 원반들이 모든 기둥을 이동할 수 있기 때문이다.
그러면 이제 다시 n-1개의 원반을 가지고 위와 같은 작업을 진행한다.
이때는 원래 보조 기둥을 시작 기둥으로, 시작 기둥을 보조 기둥으로 생각해야 한다.
1
move(원반개수-1, 보조, 시작, 목표);
Recursive frame의 내용을 완성해보자.1
2
3
4
5
6
7
8
9void move(int count, int start, int temp, int goal) {
if(count == 1) {
// start -> goal
return;
}
move(count-1, start, goal, temp); // start->temp
// start -> goal
move(count-1, temp, start, goal); // temp->goal
}
주석으로 되어 있는 부분은 실질적으로 어떤 기둥에서 어떤 기둥으로 원반이 움직였는지를 나타내는 부분이다.
좀 더 깊은 이해를 위해 원반의 개수가 3개일 때 재귀함수 호출 순서를 작성하였다.1
2
3
4
5
6
7
8
9
10
11
12
13
14move(3, 1, 2, 3)
move(2, 1, 3, 2) // 1, 2번 원반이 2번 기둥으로 가는 과정
move(1, 1, 2, 3)
1에서 3으로 이동 (1번 원반)
1에서 2로 이동 (2번 원반)
move(1, 3, 1, 2)
3에서 2로 이동(1번 원반)
1에서 3으로 이동(3번 원반)
move(2, 2, 1, 3) // 1, 2번 원반이 3번 기둥으로 가는 과정
move(1, 2, 3, 1)
2에서 1로 이동(1번 원반)
2에서 3으로 이동(2번 원반)
move(1, 1, 2, 3)
1에서 3으로 이동 (1번 원반)
1 |
|
이동 횟수부터 출력해야 하므로, pair를 만들어 vector에 넣어주었다.
즉, y좌표 오름차순(같다면 x좌표 오름차순)으로 정렬하는 문제이다.
iostream 헤더 파일의 cin과 cout을 쓰면 시간초과 되기에 cstdio를 사용하였다.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
using namespace std;
vector<vector<int>> positions;
int main() {
int n, x, y;
scanf(" %d", &n);
positions.resize(n);
for(int i = 0; i < n; ++i) {
scanf(" %d %d", &x, &y);
positions[i].push_back(y);
positions[i].push_back(x);
}
sort(positions.begin(), positions.end());
for(auto v : positions) {
for(int i = v.size()-1; i >= 0; --i) {
printf("%d ", v[i]);
}
printf("\n");
}
return 0;
}
92ms가 상당히 빠른 것은 아니기에 다른 최적의 정렬 방법이 있을지도 모른다.
1 |
|
입력
12*6의 문자
.은 빈공간
이외 뿌요 색깔 R, G, B, P, Y
뿌요들이 전부 아래로 떨어진 뒤의 상태가 주어짐
Goal: 몇 연쇄가 되는지 출력, 안터지면 0 출력
다음과 같은 과정이 일어난다.
BFS를 활용하여 4개 이상 연속인지 확인을 한다.
void bfs(현재 위치)
탐색용도 queue와 지울(터뜨릴)용도 queue 선언
현재 위치 넣어주고, check
탐색용도 queue를 전부 비울 때까지 탐색
탐색이 끝나면(더이상 갈 때가 없는 것)
지울 용도의 queue 크기가 4이상이면 터뜨리기
bfs 탐색이 끝나면 다음과 같이 4개 연속인 것들 터뜨리기
1 | void changeMap(queue<pair<int, int>> &erase) { |
이 과정이 모든 map의 각 행과 열에서 이루어지면 그때 아래로 떨어뜨린다.
(모든 위치에서 BFS탐색이 끝난 경우)
아래로 떨어뜨리기
1 | void update() { |
1 |
|
BFS를 사용하여 쉽게 풀었다..(진작에 할걸)
1 |
|
1 |
|
Y.....
B.....
R.R...
G.R...
YG....
YBR..Y
RR...Y
YYRBRB
YRBGBB
GBRBGR
GBRBGR
GBRBGR
......
......
......
......
......
......
......
......
R.....
......
RRYYGG
RRYYGG
......
..R...
..R.GG
...GG.
..R...
......
..R...
......
R.....
....G.
RRY..G
RRYYGG
Goal: K를 만드는데 필요한 동전 개수의 최솟값 구하기
동전의 가치는 오름차순으로 주어지고
이전 가치보다 항상 몇 배 더 크다.
4200
1000 4
100 2
6개
4790
4000 4 790
500 1 290
100 2 90
50 1 40
10 * 4
12개
12
1, 3, 4, 5
5 2 2
1 2
4개
하지만
4 * 3
3개
위와 같은 상황이 일어날까?
동전의 가치가 이전 가치의 배수이기에 일어날 수 없을 것이다.
1 |
|
Goal : 주어진 수를 오름차순으로 정렬하기
1 |
|
1 |
|
Next = (Now % 1000 * 10) + (Now / 1000)
Next = (Now / 10) + (Now % 10 * 1000)
테스트 케이스를 여러 번 수행하는 문제이므로 초기화가 필요한 변수나 배열은 초기화를 해줘야 한다.
명령어를 저장하고 있어야 하므로, 해당 숫자를 어떻게 만들었는지 경로를 저장할 배열을, 그 숫자를 만들 때 쓴 명령어가 무엇인지 저장할 배열을 만든다.
from[a] = b
a를 만들기 이전 숫자 b
how[a] = 'b'
a를 만들 때 수행된 명령어 b
1 |
|
1 |
|