1. 문제

1) 문제 링크

    : www.acmicpc.net/problem/17070

 

17070번: 파이프 옮기기 1

유현이가 새 집으로 이사했다. 새 집의 크기는 N×N의 격자판으로 나타낼 수 있고, 1×1크기의 정사각형 칸으로 나누어져 있다. 각각의 칸은 (r, c)로 나타낼 수 있다. 여기서 r은 행의 번호, c는 열의

www.acmicpc.net

 

2) 설명

길이 2의 파이프가 있다.

파이프는 가로, 세로, 대각선(좌상단 -> 우하단) 방향으로 밀 수 있다.

처음에 (1, 1), (1, 2)에 놓여진 파이프를 (N, M)까지 미는 경우의 수를 구하면 된다.

단 파이프는 오른쪽, 아래쪽, 대각선으로만 밀 수 있고, 직각으로는(가로 -> 세로, 세로->가로) 밀 수 없다.

또한 파이프의 이동 경로는 반드시 빈 칸이어야 하고, 대각선의 경우에는 파이프가 놓여져 있는 총 4칸이 빈 칸이어야 한다.

2. 풀이

1) 알고리즘

    : DP

 

2) 풀이 설명

3차원 DP 벡터를 사용했다.

예를 들어 dp[x][y][z]는 x 방식(0 : 가로, 1 : 세로, 2 : 대각선)으로 (y, z)에 도달하는 경우의 수를 나타낸다.

2차원 DP를 사용하지 않고 이동 방식까지 나누어 3차 DP를 사용한 이유는 이동 방식(가로, 세로, 대각선)에 따라 다음에 이동할 수 있는 방식이 달라지기 때문이다.

 

모든 dp를 0으로 초기화해주고 가로 방식의 첫 행만 1로 초기화해주었다.

 

(i, j)로 이동하는 경우의 수는 다음과 같다.

1. (i, j-1)에서 가로 이동 (단 (i, j-1)에서는 세로로 도달했으면 안 된다.)

2. (i-1, j)에서 세로 이동 (단 (i-1, j)에서는 가로로 도달했으면 안 된다.)

3. (i-1, j-1)에서 대각선 이동

 

그러므로 점화식은 다음과 같이 세워진다.

dp[0][i][j] = dp[0][i][j-1] + dp[2][i][j-1]

dp[1][i][j] = dp[1][i-1][j] + dp[2][i-1][j]

dp[2][i][j] = dp[0][i-1][j-1] + dp[1][i-1][j-1] (단 좌하단, 우상단이 빈 공간일 때)

 

이렇게 다 돌고나면

dp[0][N][M] // 마지막에 가로 방식으로 (N, M)에 도달하는 경우의 수

+ dp[0][N][M] // 마지막에 세로 방식으로 (N, M)에 도달하는 경우의 수

+ dp[0][N][M] // 마지막에 대각선 방식으로 (N, M)에 도달하는 경우의 수

 

이 답이 된다.

 

3. 코드

더보기

 

/*
	파이프 옮기기 1
	알고리즘
*/
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	
	int N, answer = 0;
	cin >> N;

	vector<vector<int>> house(N+1, vector<int>(N+1));
	/*
		0 - 가로
		1 - 세로
		2 - 대각선
	*/
	vector<vector<vector<int>>> dp(3,vector<vector<int>>(N+1, vector<int>(N+1, 0)));

	for(int i=1;i<=N;i++)
		for(int j=1;j<=N;j++)
			cin >> house[i][j];

	for(int i=2;i<=N && !house[1][i];i++)
		dp[0][1][i] = 1;

	for(int i=2;i<=N;i++){
		for(int j=2;j<=N;j++){
			if(!house[i][j]){
				dp[0][i][j] = dp[0][i][j-1] + dp[2][i][j-1];
				dp[1][i][j] = dp[1][i-1][j] + dp[2][i-1][j];
				if(!house[i-1][j] && !house[i][j-1]){
					dp[2][i][j] = dp[0][i-1][j-1] + dp[1][i-1][j-1] + dp[2][i-1][j-1];
				}
			}
		}
	}
	for(int i=0;i<3;i++)
		answer += dp[i][N][N];
	
	cout << answer << endl;

	return 0;
}

 

4. 느낀점

 - 초기에 (1, 1), (1, 2)에 파이프가 놓여져있다는 걸 모르고 가로, 세로, 대각선 다 출발했다가 틀렸다. 역시 문제를 잘 읽어야 한다.

'알고리즘 > 백준' 카테고리의 다른 글

[백준/11501] 주식  (0) 2020.10.18
[백준/15312] 이름 궁합  (1) 2020.10.18
[백준/5557] 1학년  (1) 2020.10.18
[백준/1261] 알고스팟  (0) 2020.10.16
[백준/9655] 돌 게임  (0) 2020.10.16

+ Recent posts