jchung0707   2년 전

저처럼 삽질하지 않게 올려드립니다...

*** 정답 주의 ***

.

.

.

.

.

.

.

.

.

.

.

.

..

Union-Find의 find를 경로 압축까지 하셨는데도 런타임 에러가 발생하면 다음과 같이 바꿔보세요.

Union-Find의 merge(union)에서 파라미터로 u, v를 받았을 때, v의 루트를 u의 루트의 자손으로 넣어주면 통과가 됩니다. 반면,  u의 루트를 v의 루트의 자손으로 넣으면 런타임 에러(StackSizeExceeded)가 발생하네요... rank 최적화(union-by-rank)도 u의 루트의 자손으로 v의 루트를 넣어주면 통과가 됩니다. 이유는 잘 모르겠네요...

bamgoesn   2년 전

해당 에러가 발생하는 코드는 특정 테스트 케이스 때문에 에러가 나는 게 아니라, 훨씬 많은 경우에서 에러가 날 것이라고 생각됩니다.

merge(u, v)에서 this.parent[_v] = _u와 this.parent[_u] = _v를 모두 시행하게 되면, 이후 find 연산을 할 때 무한 재귀가 발생하게 됩니다.

어느 시점에서 merge(10, 100)를 수행했을 때 10, 100의 루트가 각각 1, 2였다고 가정하고, 이후 find(2)를 호출한 상황을 가정해봅시다. 그러면 this.parent[2]는 1, this.parent[1]은 2로 설정되어 있는 상태에서, find(2)는 this.parent[2]!=2임을 확인하고 this.find(this.parent[2]) 즉 this.find(1)을 호출할 것입니다. 그러면 find(1)은 this.parent[1]!=1임을 확인하고 this.find(this.parent[1]) 즉 this.find(2)를 호출할 것입니다. 다시 find(2)로 돌아와서 find(1)을 호출하고, find(1)에서 find(2)를 호출하고... 이렇게 재귀가 무한히 반복되어 스택 오버플로우가 발생할 겁니다.

이때문에 해당 문제가 발생한 것으로, 몇몇 간단한 케이스에 대해 merge 한두 번 시행 후 find를 시도하시면 무한 재귀가 발생하는 상황이 쉽게 일어남을 확인하실 수 있습니다. 때문에 특별히 이를 저격하는 테스트케이스가 있던 것으로 보기는 어렵다고 생각합니다.

댓글을 작성하려면 로그인해야 합니다.