$N \times N$ 격자판에 $M$마리의 상어가. 각 상어는 방향과 번호를 갖는다. 매 초 다음의 일들이 일어난다.
먼저, 각 상어가 있는 칸에 그 상어의 냄새가 뿌려진다. 이 냄새는 $K$초 뒤에 사라진다.
그 다음, 상어들이 움직이는데, 모든 상어는 동시에 움직인다. 인접한 냄새가 없는 칸이 있다면 그 칸으로 움직이고, 없다면 자신의 냄새가 있는 칸으로 움직인다. 만약 가능한 칸이 여러개라면 우선순위대로 움직인다.
모든 상어가 움직인 다음, 만약 둘 이상의 상어가 겹쳐있다면 번호가 가장 작은 상어만 남고 나머지는 쫓겨난다.
이때, 1번 상어만 남게 되는 시간을 구하는 문제이다.
접근
으레 그렇듯이 구현만 잘 하면 된다. 여러 방법으로 구현할 수 있겠지만, 나는 다음과 같이 구현하였다.
상어의 현재 위치를 저장하는 2차원 shark리스트, 남아 있는 냄새를 [번호, 남은 시간]꼴로 저장할 3차원 board리스트, 각 상어의 방향을 저장할 direction리스트, 각 상어의 방향 우선순위를 저장해 놓는 prefer리스트를 만든다. 또, 상어 수를 저장할 count를 $M$으로 초기화 해 둔다.
$t=1$부터 $t=1000$까지 다음을 반복한다:
shark리스트를 돌면서 상어들의 현재 위치를 찾아서, board리스트의 각 위치에 남은시간 $K$짜리 냄새를 만든다.
그 다음 상어를 움직이는데, 먼저 상어가 한번에 움직이도록 하기 위해 모든 칸이 빈 칸, 즉 [-1,-1]으로 저장되어있는 new_board리스트를 만든다.
각 상어에 대해서, 만약 아직 존재한다면(shark[i][0]!=-1)
direction리스트에서 현재 방향을 가져오고, 이를 이용해 prefer리스트의 네 방향을 우선순위 순서대로 살펴본다.
만약 냄새가 없는 칸을 만나면, 그 칸이 가장 우선순위가 높은 칸이므로 즉시 break해준다.
자신의 냄새가 있는 칸을 만나면, 가장 먼저 만나는 하나만 저장해 놓는다.
냄새가 없는 칸이 없었다면, 자신의 냄새였던 칸을 목표로 한다. 없었다면 냄새가 없는 그 칸이 목표이다.
목표하는 칸으로 상어를 이동시킨다. direction을 바꿔주고, shark리스트에 저장된 위치를 바꿔준다.
new_board리스트의 새 위치에 상어 번호를 [num, -1]꼴로 적어준다. 만약 이미 그 자리에 상어 번호가 적혀있다면, 두 번호를 비교해서 낮은 번호를 놔두고, 높은 번호는 없애준다. shark리스트에 [-1,-1]을 넣어 쫓겨났음을 표시한다. 이때 count도 1 줄어든다.
마지막으로, board리스트에서 냄새를 1씩 줄여 new_board로 옮겨준다.
new_board를 board에 새로 assign한다.
만약 상어 수가 1이라면, 현재 시간을 출력하고 끝낸다.
$t=1000$까지 상어 수가 여러 마리라면, -1을 출력한다.
주의할 점
비어있는 칸, 잡아먹힌 상어, 냄새 등을 어떤 형식으로 저장할 지 잘 생각해보아야 한다.
1번 상어만 남는 경우와 상어 수가 1인 상태는 완벽히 동일하므로, 매 루프마다 각 상어의 상태를 확인할 필요 없이 상어 수만 세어도 충분하다.