[1. 문제 재정의 및 추상화]
- 각 스위치들은 모두 적게는 3개에서 많게는 5개의 시계가 연결되어 있다.
- 한 스위치를 누를때마다 연결된 시계는 3시간씩 앞으로 움직임 (3->6, 6->9, 9->12, 12->3)
- 모든 시계를 12시로 돌려놓기 위해 스위치를 눌러야 할 최소 횟수를 출력해야 함
- 불가능 할 경우 -1을 출력
[2. 해결 계획]
- 경우의 수가 아니라 최소 횟수를 계산해야 함
- 그러나 일단 시작은 완전 탐색에서 시작해보도록
- 스위치를 누르는 순서는 중요하지 않다?
[3. 계획 검증]
- 동일한 스위치를 4번 누르면 결국 처음 상태와 같아짐.
- 따라서 완전탐색으로 진행 시 전체 경우의 수는 4^10=1,048,576 으로 완전 탐색으로도 충분해 보임
[4. 구현]
#include <iostream>
#include <vector>
#include <algorithm>
constexpr const int SWITCHS = 10;
constexpr const int CLOCKS = 16;
const int INF = 987654321;
const int LINKS[SWITCHS][CLOCKS] = {
// 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
/*00*/ {1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
/*01*/ {0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0},
/*02*/ {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1},
/*03*/ {1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0},
/*04*/ {0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0},
/*05*/ {1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1},
/*06*/ {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1},
/*07*/ {0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1},
/*08*/ {0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
/*09*/ {0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}
};
const int NEXTHOUR[12+1] = {
// 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
0, 0, 0, 6, 0, 0, 9, 0, 0, 12, 0, 0, 3
};
void push_switch(std::vector<int>& clocks, const int switch_no)
{
// 모든 시계에 대해서
for (int idx = 0; idx < clocks.size(); idx++)
{
// 해당 스위치에 연결된 경우
if (LINKS[switch_no][idx])
{
// 시간을 바꿈.
clocks[idx] = NEXTHOUR[clocks[idx]];
}
}
}
int solve(std::vector<int>& clocks, const int switch_no)
{
// Base Case 1
if (std::all_of(clocks.begin(), clocks.end(),
[](const int clock){return clock == 12;}))
{
return 0;
}
// Base Case 2
// 모든 switch 를 눌렀는데, 모든 시계가 12시가 아님
if (switch_no == SWITCHS)
{
return INF;
}
int ret = INF;
// 현재 스위치를 한번도 누르지 않는 경우 부터
// 최대 3번까지 누르는 경우를 확인
for (int push = 0; push < 4; push++)
{
const int recursion_ret = solve(clocks, switch_no + 1);
// 모두 12시로 바뀔 수 있는 경우에 대해서만 ret 값을 업데이트 함.
// INF 는 전체 경우의 수 보다 큰 값.
ret = (recursion_ret != INF) ? std::min(ret, push + recursion_ret) : ret;
// 4번째 실행 시 다시 처음 상태로 되돌아 옴.
push_switch(clocks, switch_no);
}
return ret;
}
int main()
{
int T;
std::vector<int> clocks(CLOCKS);
scanf("%d", &T);
for (int t = 0; t < T; t++)
{
int clock;
for (int c = 0; c < CLOCKS; c++)
{
scanf("%d", &clock);
clocks[c] = clock;
}
const int ret = solve(clocks, 0);
printf("%d\n", ret == INF ? -1 : ret);
}
return 0;
}
'알고리즘 > Algospot' 카테고리의 다른 글
[분할 정복] FENCE (0) | 2022.02.14 |
---|---|
[분할 정복] QUADTREE (0) | 2022.02.05 |
[완전 탐색] BOARDCOVER (0) | 2022.02.04 |
[완전 탐색] PICNIC (0) | 2022.02.04 |
알고리즘 분석 (0) | 2022.02.04 |