문제 링크
- https://icpc.me/18447
사용 알고리즘
- 일반 그래프 매칭
풀이
*
에는 항상 L 형태의 블록을 배치해야 하고, +
에는 I와 L 중 원하는 것을 배치할 수 있습니다. *
와 +
모두 인접한 네 칸 중 정확히 두 칸과 매칭되어야 합니다.
.
이 아닌 격자의 각 칸 $(i, j)$마다 2개의 정점 $(i, j, 0), (i, j, 1)$을 만들 것입니다.
$A(i,j)=\ast$ 이면 $(i,j)$는 위/아래 중 하나, 그리고 왼쪽/오른쪽 중 하나와 연결되어야 합니다. $(i,j,0)$을 $(i-1,j,0), (i+1,j,0)$과 연결하고, $(i,j,1)$은 $(i,j-1,0), (i,j+1,0)$과 연결합시다.
$A(i,j)=+$ 이면 $(i,j)$는 인접한 네 칸 중 아무거나 두 개를 선택해서 연결하면 됩니다. $(i,j,0)$과 $(i,j,1)$ 모두 인접한 네 칸의 격자 칸과 연결합시다.
격자를 블록으로 채우기 위해서는, .
이 아닌 칸이 모두 두 개의 정점과 매칭되어야 하고, 이는 .
이 아닌 칸마다 간선이 2개씩 연결되는 최대 매칭을 찾으면 됩니다. 이런 문제는 NERC’18 Bimatching이라는 문제로 잘 알려져 있고, 일반 그래프 매칭으로 해결하는 방법이 koosaga님 블로그에 잘 설명되어 있습니다.
구현은 아래 코드의 15~36번 줄을 참고하시면 됩니다.
아무튼 매칭을 구했다면, 이제 출력을 해야 합니다. 인접한 블록을 서로 다른 알파벳으로 출력해야 합니다.
많이 귀찮을 것 같지만 격자 그래프가 평면 그래프라는 점을 이용하면 어렵지 않습니다. 평면 그래프에는 항상 차수가 5 이하인 정점이 존재하기 때문에, 차수가 최소인 정점을 찾아서 하나씩 제거하는 방식으로 정점을 색칠할 수 있습니다.
자세한 방법은 아래 코드의 48번째 줄 이후를 확인하시면 됩니다.
전체 코드
1 |
|