기본 아이디어는 쉽게 얻었으나, 실제 구현하는 과정에서 삽질한 사례 소개. 강한 스포일러가 포함되어 있으니 위 문제를 풀 생각이 있는 사람이라면 스킵하는 것을 권장합니다.
링크 참조
room A와 B가 각각 서로 다른 갯수의 문을 갖고 있다면, 두 개의 방은 서로 구분가능하다. 이어서 A로 연결되는 임의의 복도 a와, B로 연결되는 임의의 복도 b 또한 서로 구분가능해 진다. 이 복도 a가 (X, A)를 연결하는 녀석이고, b는 (Y, B)를 연결하는 녀석이라고 하자. 이때 X, Y 만으로는 서로 구분하는 것이 불가능하지만, 다음과 같이 다른 경로들을 서로 구분가능한 것으로 결정할 수 있다.
Image hosted for free at CtrlV.in
X, Y가 각각 3개의 문을 갖고있는 경우라고 한다면, a1과 b1은 서로 구분가능한 복도가 된다.(해당 경로를 다 걸어간 다음, 도달한 방에서 바로 오른쪽에 있는 문을 열고 이동하면 서로 다른 A 혹은 B 방이 나와 자기가 a1에 있는지, b1에 있는지 구분가능해진다. a2, b2도 마찬가지. 결국 어떤 구분가능한 복도쌍을 가지고 있는 경우 다른 구분가능한 복도쌍을 만들어나갈 수 있고, 이것들을 통해 모든 구분가능한 복도쌍을 계산해낼 수 있게 된다.
구분가능한 복도쌍을 만들어낸 이후, 방과 방을 서로 구분하는 것은 비교적 trivial한 문제다. 일단 서로 문 갯수가 다르면 당연히 서로 구분가능한 방들인 것이고, 같은 경우, 한바퀴 돌면서 순서대로 문을 매칭했을 때 모두 구분 불가능한 경우가 있다면 두 방을 구분할 수 없는 것이고, 그런 경우가 없다면 두 방을 구분할 방법이 있다는 것이렷다.
위 아이디어를 가급적 그대로 구현한 코드는 아래와 같다.
https://gist.github.com/blmarket/d027d3a998dca0262d9f#file-e-fail-cc
이 코드는 두 가지가 틀렸다. 먼저, 문 갯수가 0개인 경우, '한바퀴 돌면서 문을 매칭'하는 과정이 아예 안돌아가는 바람에 두 방을 구분할 수 있다는 것으로 나와버렸고, 그 다음에는 call stack이 깊게 들어가지면서 segmentation fault가 발생하는 경우가 있었다.
https://gist.github.com/blmarket/d027d3a998dca0262d9f#file-e2-success-cc
위에서 발생한 버그들을 아이디어를 유지하면서 수정한 코드. 근데 어디서 틀렸는지 알 수가 없는 대회 환경에선 이런 버그 잡기 정말 어려워진다. 아이디어 단계에서부터 좀 더 쉽게 구현가능한 레벨의 아이디어를 고민했다면, 좀 더 버그 잡기 쉬운 풀이가 가능했을 것이다.
https://gist.github.com/blmarket/d027d3a998dca0262d9f#file-ee-cc
bmerry의 블로그 글을 읽고 다시 풀어본 코드. iteration을 돌면서 라벨링을 수행하기 때문에, 버그가 있더라도 중간중간 라벨링을 찍어보는 것이 가능하다.
Written with StackEdit.