백준 15684 - 사다리 조작

2 minute read

문제링크

문제설명

  • 사다리 게임으로 N개의 세로선, M개의 가로선을 놓을 수 있다.
  • H는 가로선을 놓을 수 있는 위치를 보여주며 모든 세로선을 가로지르는 점선의 개수이다.
  • 세로선의 개수, 가로선의 개수, 그리고 H가 주어진 사다리 상황에서 최대 3개의 가로선을 추가할 수 있는데, i번 세로선에서 출발해서 i번에 도착하도록 만들기 위한 추가해야 하는 가로선의 최솟값을 찾아라.
  • 정답이 3보다 크거나, 불가능한 경우 -1을 출력하라.

입력

  • 세로선 개수(N), 가로선 개수(M), 세로선마다 가로선을 놓을 수 있는 위치 개수(H)가 주어짐
  • M개의 줄에 걸쳐 가로선의 정보가 한 줄에 하나씩 주어진다. (a, b)
    • b번 세로선과 b+1번 세로선을 a번 점선 위치에서 연결했다는 의미

문제접근

  • Dfs를 적용하는 방법을 고민할 때, 시간 복잡도를 고려하다보니 이중반복문의 Dfs를 활용하겠다는 생각은 가장 마지막 순서였다.
  • 문제의 시간제한은 2초로 주어졌고, 최대 3개까지만 놓을 수 있으니 이중반복문의 Dfs를 적용하여 문제를 풀 수 있다는 생각이 들었다.
  • 기저사례는 이미 답을 구한 경우이거나 추가 가로선을 모두 놓은 경우이다.
  • ladder[row][col]=1 은 row번 점선 위치에서 세로선 col, col+1번이 연결되었음을 의미한다.
  • 추가 가로선은 ladder[row][col]을 기준으로 좌측, 우측에 위치한 사다리에 가로선이 없을 때만 놓을 수 있다.
  • 사다리 타기를 함수로 구현할 때는 ladder[row][col]=1 인 경우 col+1로 이동해야하고, ladder[row][col-1]=1 인 경우 col-1로 이동해야한다.

구현 1(All Pass)

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

bool CheckLadder(vector<vector<int>>& ladder) {
	int h = ladder.size(); // 가로 점선
	int n = ladder[0].size(); // 세로선

	for (int c = 1; c < n-1; c++) { // 1 ~ n-1
		int ccol = c;
		for (int r = 1; r < h; r++) { // 1 ~ h
			int left = ccol - 1;
			if (ladder[r][left] == 1) ccol = left;
			else if (ladder[r][ccol] == 1) ccol++;
		}
		if (ccol != c) return false;
	}
	return true;
}

void Dfs(vector<vector<int>>& ladder, int cnt, int m, bool& flag) {
	// 기저사례: 이미 답을 구한 경우
	if (flag) return;

	// 기저사례: cnt==m, 추가 사다리를 모두 놓은 경우
	if (cnt == m) {
		if (CheckLadder(ladder)) {
			flag = true;
			return;
		}
		return;
	}
	
	int h = ladder.size(); // h+1
	int n = ladder[0].size();
	for (int c = 1; c < n-1; c++) { // 1 ~ n-1
		for (int r = 1; r < h; r++) { // 1~h
			int left = c - 1;
			int right = c + 1;
			if (ladder[r][left] || ladder[r][right] || ladder[r][c]) continue;
			ladder[r][c] = 1;
			Dfs(ladder, cnt + 1, m, flag);
			ladder[r][c] = 0;
		}
	}
}

int main()
{
	cin.tie(NULL);
	ios_base::sync_with_stdio(false);
	int N, M, H, a, b;
	cin >> N >> M >> H;

	// b번 세로선과, b+1번 세로선을 a번 점선 위치에서 연결
	// ladder[a][b] = 1
	vector<vector<int>> ladder(H + 1, vector<int>(N+1, 0));
	for (int i = 0; i < M; i++) {
		cin >> a >> b;
		ladder[a][b] = 1;
	}

	bool flag = false;
	int ans = -1;
	for (int m = 0; m < 4; m++) {
		Dfs(ladder, 0, m, flag);
		if (flag) {
			ans = m;
			break;
		}
	}
	cout << ans << endl;
	return 0;

}
  • 처리시간을 줄이기 위해 답을 찾은 경우 빠르게 함수를 빠져나오도록 flag 장치를 두었다.

Leave a comment