[삼성코테기출문제] 경사로

3 분 소요

경사로

문제

시뮬레이션 문제이다. 단순히 보면 쉬운 문제로 착각하기 쉽다. 그냥 행이나 열로 처음부터 끝까지 갈 수 있냐? 갈 수 없으면 주어진 경사로를 놓아라, 경사로를 놓지 못하거나 놓아도 갈 수 없는 길이면 지나갈 수 없는 길이다.
하지만 경사로를 놓는 조건을 구현하는 것이 생각보다 까다로웠다. 처음에 문제를 풀 때 생각한 조건을 구현하고 빠진 조건이 있으면 추가하면서 하니 코드가 너무 길어졌다. 물론 답도 나오지 않았다. 시뮬레이션문제는 이런 부분이 어려운 것 같다, 빠진 조건을 추가하다보면 코드가 꼬이는 일이 생기고 결국 시간 안에 문제를 풀지 못하는…
물론 많은 연습이 있다면 나아지겠지만 아직까진 좀 부족한것 같다.

문제
문제
문제

문제 풀이

이 문제는 다시 풀으라고하면 힘들것 같다. 풀다가 안풀려서 다 지우고 모든 조건을 다시 생각해가며 코드를 짯다. 이 문제의 keypoint는 경사로에 대한 조건을 잘 생각해서 예외가 일어나지 않게 짜는 것이 중요한 것 같다.

입출력 조건
입력

풀이 과정

  1. 맵에 대한 정보를 받고 에 대해서 탐색할 것인지, 에 대해서 탐색할 것인지를 판단하여 이면 true를 넘겨주고 이면 false를 넘겨주어서 탐색을 시작한다.
    slope(int i, bool c)에서 bool은 행이냐? 열이냐?를 의미하고, i는 몇번째냐?를 의미한다.
  2. 해당 길에 한 칸 들어왔으므로 cnt는 1부터 시작하고, 다음 칸을 의미하는 j로 반복문을 이용하여 한 칸 한 칸 탐색한다.
  3. d는 현재 칸과 다음 칸을 행과 열에 따라 계산하여 받는 변수 이다. 이 때 d의 조건으로 경사로를 세울 수 있냐? 경사로를 세우는 중이냐? 를 판단할 것이다.
    • d=0이면 현재 칸과 다음 칸의 차이가 없으므로 움직일 수 있다. 따라서 한 칸 움직였다는 의미인 cnt를 1증가 시켜준다.
    • d=1 and cnt >= L이면 현재 칸과 다음 칸의 차이는 1이고 다음 칸이 더 높다는 뜻이다. 따라서 현재까지 지나온 길이 경사로의 길이(L)보다 같거나 길어야 경사로를 세울 수 있으므로 cnt>=L의 조건도 같이 확인한다.
    • d=-1 and cnt>=0이면 현재 칸과 다음 칸의 차이는 -1이고 다음 칸이 더 낮다는 뜻이다. 따라서 다음 칸들이 계속해서 갈 수 있는 길이어야한다. 그리고 아직 다음 칸으로 넘어가지 않았으므로 cnt>=0이어야 한다.
    • else 나머지인 경우는 경사로를 세울 수 없으므로 현재 재귀함수를 종료한다.
    • 예를 들어보자.
      L=2, 2233223 인 길이 있다. 현재 칸(이하 c), 다음 칸(이하 n),갈 수 있으면 OK, 못 가면 NO라고 할 때
      c=2, n=2, d=0, cnt=1 OK cnt++
      c=2, n=3, d=1, cnt=2 (cnt>=L에 만족) OK cnt=1
      c=3, n=3, d=0, cnt=1 OK cnt++
      c=3, n=2, d=-1,cnt=2 (cnt>=0에 만족 일단 내려가는 경사로를 세움) cnt = -L+1 -> cnt=-1
      c=2, n=2, d=0, cnt=-1 (경사로를 세우는 중)cnt++
      c=2, n=3, d=1, cnt=0 (d=1 and cnt >= L에 만족하지 못 함)NO
      내려가는 경사로를 음수를 이용하여 계산하여 경사로를 다 세우면 cnt=0이 되게하여 다음 경사로를 생각해준다 따라서 이 길은 갈 수 없는 길이다.
      만약 이 길이 223322223이라면 (d=1 and cnt >= L에 만족하므로) OK가 되어 갈 수 있는 길이 된다.
  4. 이 과정을 반복하여 갈 수 있는 길을 카운트하여 답을 낸다.

#include <iostream>
using namespace std;

const int MAX = 100;
int N, L, ans;
int Map[MAX][MAX];

void Input() {
	cin >> N >> L;
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < N; j++) {
			cin >> Map[i][j];
		}
	}
}
/*
D가 0이라면, 길의 높이가 같은 경우이다.
D가 1이라면, 올라가는 경사로가 필요한 경우이다.
D가 -1이라면, 내려가는 경사로가 필요한 경우이다.
길의 높이가 같다면 (D == 0), 카운트를 1 증가시킨다. 카운트는 경사로의 길이와 비교하기 위해 필요하다.
올라가는 경사로라면 (D == 1), 카운트가 경사로의 길이 L 이상인지 확인한다. 카운트가 L 이상이라면,
경사로를 놓을 수 있는 경우이므로, 카운트를 1로 초기화시킨다.
내려가는 경사로라면 (D == -1), 카운트가 0 이상인지 확인한다. 
0 이상이라면, 카운트를 경사로의 길이 L만큼을 음수로 만든다. 
만약 카운트가 음수라면, 내려가는 경사로를 만들고 있는 중이므로, 경사로를 놓을 수 없다.
*/
void slope(int i, bool c) {
	int cnt = 1;
	for (int j = 0; j < N - 1; j++) {
		//행이냐 열이냐
		int d = c == true ? Map[i][j + 1] - Map[i][j] : Map[j + 1][i] - Map[j][i];
		if (d == 0) cnt++;
		else if (d == 1 && cnt >= L) cnt = 1;
		else if (d == -1 && cnt >= 0) cnt = -L + 1;
		else return;
	}
	if (cnt >= 0) ans += 1;
}
void Process() {
	for (int i = 0; i < N; i++) {
		slope(i, true);
		slope(i, false);
	}
}
void Solution() {
	Input();
	Process();
	cout << ans << "\n";
}
int main() {
	freopen("12.in", "r", stdin);
	cin.tie(NULL);
	ios::sync_with_stdio(false);
	Solution();
	return 0;
}

댓글남기기