양과 늑대는 서로 천적인가 봅니다.
레이튼교수 시리즈에도 양과 늑대를 가지고 강을 건너는
이 문제와 상당히 유사했던 문제가 있었습니다.
이 문제의 시작은 0번 정점은 항상 양으로 시작합니다.
당연히 늑대로 1빠따로 시작하면 양을 한 마리도 못 모으기 때문이죠.
그럼 우리는 답을 전부 0으로 제출하면 되니까 개꿀이기는 하지만, 카카오로 상대로는 어림도 없습니다.
아쉽게도 양이 항상 0번 노드를 차지해서 양을 모으는 경우의 수가 생기겠군요 ㅠㅠ
단순히 생각해봐도, 완전탐색에 해당되는 문제입니다.
그것도 모든 경우의 수를 탐색하는 문제가 됩니다.
따라서 BFS나 DFS나 어떤 걸 사용하셔도 무방하지만,
사실 BFS를 사용하려면 큐도 소환해야하고, 데이터 푸쉬하고, 팝하고 어지간히 귀찮습니다.
그냥 간단하게 DFS를 사용하여 구현하는 것이 편할겁니다.
그럼 우리는 이제 DFS를 어떤식으로 돌리면 좋을까? 라는 생각을 먼저 하게 됩니다.
이 문제를 보자면, 이미 지났던 정점들을 다시 한 번 지나가서 반대편으로 넘어가서 양을 데려오기도 하고,
아무튼, 역류해서 다시 다른 쪽으로 지나가는 상황이 연출되는 것을 쉽게 알 수 있습니다.
그래서 대부분, 양방향 그래프를 사용해야겠군, 이라고 생각하여, 코딩을 하다가, 재귀호출스택을 초과하거나,
실행시간 10초를 넘겨 프로그래머스 채점 시스템한테 엄청난 싸다구를 맞게 됩니다.
근데 단순히 생각해보자면, 이미 지나갔던 정점은 생각해봤을 때, 다시 방문하더라도,
아무런 변화가 없습니다. 왜냐하면 최초방문시에 해다 정점에 서식했던 동물이 따라오게 때문이고,
그게 게임이 끝날 때 까지 계속 따라 다니기 때문입니다. 같은 정점을 다시 방문해도 결국에는, 아무런 의미가 없습니다.
그럼 우리는 굳이 양방향 그래프를 써가면서, 무한적인 재귀호출을 만들 필요는 없습니다.
그러면, 단방향 그래프를 통하여, 재귀호출을 구현할 수 있는 방법을 찾을 필요가 존재합니다.
바로 그 답은, 다음 차례에 이동 가능한 정점을 따로 담아서 재귀호출을 하는 것입니다.
자, 첫번째 테스트 케이스를 예시로 들어보도록 하겠습니다.
0번 정점은 1번과 8번 정점을 자식으로 두고 있습니다. 즉, 쉽게 말하면, 0번 정점을 한 번 들렸다는 의미는,
1번과 8번 정점을 다시 언제든지 방문할 수 있게 됩니다. 부모 정점을 방문하여 이미 길이 만들어졌으면,
그 부모 정점의 하나 바로 밑에 존재하는 자식 정점들은 언제든지 입장이 가능하게 됩니다.
그럼 만약에 1번과 8번 정점을 갈 수 있다고 하면 나는 지금 당장 8번 정점으로 이동한다고 가정하여 봅시다.
다음에 갈 수 있는 정점은 [1, 8] 에서 [1, 7, 9] 정점이 됩니다. 0번 정점을 최초로 방문한 후에
다음에 갈 수 있는 정점을 계산하면, [1, 8]번 정점을 방문할 수 있게 됩니다. 또한 8번 정점을 방문하게 되면,
8번 정점을 리스트에서 제하고(방문했으므로) 8번 정점의 자식들인 7번과 9번 정점이 추가 되어서,
최종적으로 [1, 7, 9]번 정점들을 방문할 수 있게 됩니다. 이런 방법이면, 굳이 그래프가 역류하는 경우를 계산 할 필요가
없게 됩니다. 또한 모든 그래프를 전부 방문하게 되면 자연스럽게 다음에 방문할 수 있는 그래프가 존재하지 않게 되므로,
재귀호출이 일어나지 않습니다.
수행 1.
수행 2.
수행 3.
수행 4.
수행 5.
주의할 점.
이동가능한 정점은 리스트의 형태로 재귀호출을 보낼 경우, 리스트가 완전 복제가 일어나지 않게 되면, 독립적 변수로 취급이 되지 않아 다른 곳에서 값을 바꾸면 연쇄적으로 이어져서 값이 바뀌어 최악의 상황을 초래하게 된다. 항상 배열이나 리스트의 자료형태를
값을 독립적으로 바꾸는 작업을 수행 할 때는, 무조건 복제를 하여 독립적 리스트로써 사용하도록 주의해야한다.
분명 말했습니다. 완탐문제에서는 이런 문제가 아주 많이 발생합니다. 주의합시다.
결과 변수의 최대값 갱신은 항상 양과 늑대의 수를 업데이트한 이후와 늑대의 수를 양의 수를 넘었는 지의 조건문을 탐색하는 그 중에 배치해야한다. 가끔 그런 분들이 있을 수 있는데, 당연히 wolf가 sheep의 수를 따라잡거나 초과하는 조건문에서만 결과 변수의 최댓값을 갱신하는 분이 있을 수 있다. 하지만 그렇게 되면, 모든 정점을 탐색하는 경우에 양의 수가 늑대의 수보다 많은 경우를 탐색하는 것이 불가능할 것이다. 이런 어이없는 경우가 생기지 않도록 조심하자.
레벨 3치고는 생각보다 어렵지 않은 문제입니다.
오히려 레벨2의 양궁 대회가 더 레벨 3과 같이 느껴집니다.
그래도 자세한 설명을 알고 싶은 여러분들을 위해서 이 글을 작성합니다.
도움이 되셨으면 댓글 부탁합니다. 또한 해설에 논리적인 에러가 보이면 그것도 지적 부탁합니다.
감사합니다
공감합니다.. 양궁문제가 이거보다 더 까다로웠던거 같아요..
감사합니다!
정점들을 새로 담아서 호출하지 않으면, 0->1의 DFS를 모두 끝내고 0->8의 DFS를 할 때 0->1에서 방문했던 노드들이 덕지덕지 붙어있어서 중복 방문하게 되더라구요. 덕분에 해결할 수 있었습니다! 이거 해결하는 더 빠른 방법으로 비트마스킹으로 메모이제이션하는 방법도 있던데, 다들 참고하시면 좋을 거 같습니다.
자세한 설명 감사합니다
카카오 해설보다 자세하게 설명해주셔서 문제 푸는데 도움이 많이 됐습니다! 감사합니다
설명이 너무 쉽게 잘되있습니다 감사합니다!!
감사합니다 도움이 되었습니다
감사합니다
좋은 해설이네요!
덕분에 큰 도움이 됐어요. 감사합니다