문제 출처 : https://www.acmicpc.net/problem/17070
17070번: 파이프 옮기기 1
유현이가 새 집으로 이사했다. 새 집의 크기는 N×N의 격자판으로 나타낼 수 있고, 1×1크기의 정사각형 칸으로 나누어져 있다. 각각의 칸은 (r, c)로 나타낼 수 있다. 여기서 r은 행의 번호, c는 열의
www.acmicpc.net
문제
유현이가 새 집으로 이사했다. 새 집의 크기는 N×N의 격자판으로 나타낼 수 있고, 1×1크기의 정사각형 칸으로 나누어져 있다. 각각의 칸은 (r, c)로 나타낼 수 있다. 여기서 r은 행의 번호, c는 열의 번호이고, 행과 열의 번호는 1부터 시작한다. 각각의 칸은 빈 칸이거나 벽이다.
오늘은 집 수리를 위해서 파이프 하나를 옮기려고 한다. 파이프는 아래와 같은 형태이고, 2개의 연속된 칸을 차지하는 크기이다.
![](https://blog.kakaocdn.net/dn/cofa3M/btruUn5AzSy/yqvhKVKnVDDnzFHPea2X5K/img.png)
파이프는 회전시킬 수 있으며, 아래와 같이 3가지 방향이 가능하다.
![](https://blog.kakaocdn.net/dn/69cNU/btruRNcBdBE/1k0cNRoqplacKT65geZrMK/img.png)
파이프는 매우 무겁기 때문에, 유현이는 파이프를 밀어서 이동시키려고 한다. 벽에는 새로운 벽지를 발랐기 때문에, 파이프가 벽을 긁으면 안 된다. 즉, 파이프는 항상 빈 칸만 차지해야 한다.
파이프를 밀 수 있는 방향은 총 3가지가 있으며, →, ↘, ↓ 방향이다. 파이프는 밀면서 회전시킬 수 있다. 회전은 45도만 회전시킬 수 있으며, 미는 방향은 오른쪽, 아래, 또는 오른쪽 아래 대각선 방향이어야 한다.
파이프가 가로로 놓여진 경우에 가능한 이동 방법은 총 2가지, 세로로 놓여진 경우에는 2가지, 대각선 방향으로 놓여진 경우에는 3가지가 있다.
아래 그림은 파이프가 놓여진 방향에 따라서 이동할 수 있는 방법을 모두 나타낸 것이고, 꼭 빈 칸이어야 하는 곳은 색으로 표시되어져 있다.
![](https://blog.kakaocdn.net/dn/DOE6m/btruMox9y7t/c0mP74Ax9V7HAhoJZiq3Z0/img.png)
![](https://blog.kakaocdn.net/dn/U0uDk/btruLuk323S/HGRkQAS4KHkxvn1fbnYWw0/img.png)
![](https://blog.kakaocdn.net/dn/b2KTm9/btruLtGt4vH/7WW25dCMHTMTeAjUdGdlC0/img.png)
가장 처음에 파이프는 (1, 1)와 (1, 2)를 차지하고 있고, 방향은 가로이다. 파이프의 한쪽 끝을 (N, N)로 이동시키는 방법의 개수를 구해보자.
입력
첫째 줄에 집의 크기 N(3 ≤ N ≤ 16)이 주어진다. 둘째 줄부터 N개의 줄에는 집의 상태가 주어진다. 빈 칸은 0, 벽은 1로 주어진다. (1, 1)과 (1, 2)는 항상 빈 칸이다.
출력
첫째 줄에 파이프의 한쪽 끝을 (N, N)으로 이동시키는 방법의 수를 출력한다. 이동시킬 수 없는 경우에는 0을 출력한다. 방법의 수는 항상 1,000,000보다 작거나 같다.
알고리즘 분류
풀이
dp 혹은 그냥 dfs로 풀 수 있다.
n의 크기가 크지 않기 때문에 그냥 dfs로도 풀리는데, 핵심은
시작 지점에서 도착지점까지 가는데 매 정점마다 현재 어떤 방향인지,
현재 방향에 따라 갈 수 있는 방향 (2가지이거나 3가지)를 모두 탐색하여 만약
다음 정점 방문이 유효하지 않다면 (벽을 만나거나 그래프를 이탈하는 경우) 스킵한다.
현재 방향에 따라 갈 수 있는 방향은 xor 연산을 이용했는데,
0, 1, 2를 가로, 세로, 대각선으로 방향으로 두고
현재 방향(direct)이 가로라면 가로, 대각선으로만 갈 수 있기 때문에
if(다음 방향 == 0 xor 1) continue
로 가로, 대각선으로만 갈 수 있게끔 구현하였다.
코드
val br = System.`in`.bufferedReader()
lateinit var graph: Array<List<Int>>
var answer=0
var n=0
val dir = arrayOf(arrayOf(0,1), arrayOf(1,0),arrayOf(1,1))
fun dfs(r: Int, c: Int, direct: Int){
if(r==n-1 && c==n-1){
answer++
return
}
for(i in 0 until 3){
if(direct xor 1 ==i) continue
val nr = r + dir[i][0]
val nc = c + dir[i][1]
if(nr !in 0 until n || nc !in 0 until n) continue
if(i==2){
if(nr-1 <0 || nc-1 < 0 || graph[nr][nc]==1 || graph[nr-1][nc] == 1 || graph[nr][nc-1] ==1) continue
}
else{
if(graph[nr][nc]==1) continue
}
dfs(nr,nc,i)
}
}
//3<=n<=16
fun main() = with(System.out.bufferedWriter()){
n = br.readLine().toInt()
graph = Array(n){br.readLine().split(' ').map{it.toInt()}}
dfs(0,1, 0)
write("$answer")
close()
}
'알고리즘 문제 풀이 > 백준' 카테고리의 다른 글
프로그래머스 [3차] 압축 Java (구현) (0) | 2022.03.10 |
---|---|
프로그래머스 주차 요금 계산 Kotlin (문자열, 시간) (0) | 2022.03.07 |
백준 19947 투자의 귀재 배주형 Kotlin(완전 탐색) (0) | 2022.02.28 |
백준 16943 숫자 재배치 Kotlin (순열) (0) | 2022.02.24 |
백준 15270 친구 팰린드롬 Kotlin (백트래킹) (0) | 2022.02.23 |
댓글