참으로 쉬운거 같으면서도 막상 풀려고하면 어려운 문제를 이런 문제 같다.
문제에 보이는 규칙을 일반화하여, 프로그래밍 언어로 작성해야한다.
딱히 시간 제한도 없기 때문에, 특정 알고리즘이 존재하는 문제도 아니다.
단순히 문제를 코드로 구현이 가능한가?를 확인해보기 위한 문제이다.
위의 두 가지 사실은 이 문제를 풀기위한 가장 기초적인 지식이다.
이 두 가지의 사실을 이용하여 우리는 데이터를 어떠한 방식으로 저장해야할 지 고민한다.
n의 값이 5이면 보드의 크기는 5*5의 사이즈가 된다. 참조할 수 범위는 0~5까지 해서
한 축에 6가지의 선택지가 주어진다.
이해하였는가? 5*5 보드인데 왜 한 축에 6가지의 선택이 가능한지가 말이다.
우리는 5*5보드라고 어떤 값을 지정하면, 배열의 격자에 저장되는 것이 아닌, 문제의 그림처럼,
그 격자 사이에 존재하는 교점좌표를 지정하는 것이다. 절대 이 부분을 착각해서는 안된다.
즉 우리는 보드를 만들 때, 애초부터 5*5가 아닌 6*6보드를 만들어서 모든 격자에 접근이 가능토록 한다.
그럼 0~5까지의 인덱스를 전부 참조할 수 있게 되어, 우리가 원하는 값들을 저장 할 수 있게된다.
이해가 어려우면 문제의 예시에 있는 그림을 살펴보자. 0부터 5까지 숫자로 써져있는 것을 볼 수 있다.
우리는 새로 만든 6*6배열을 통해 0부터 5까지의 인덱스에 모두 접근 가능함으로써, 5*5 보드의 모든 교점좌표를
저장하는 것이 가능해진다.
그렇지만, 보드는 하나만 필요한 것일까? 우리는 기둥과 보가 한 교점좌표에 존재한다는 사실을 알고있다.
만약 (0, 0)좌표에 기둥을 세우고, (0, 1)에 보를 세웠다고 하자. (0, 1)에 보를 세웠다고 해서, (0, 1)좌표에 기둥을
못세우는가? 그렇지 않다. 그림을 그려봐도, (0, 1)교점 좌표에 기둥또한 세울 수 있다. 그럼 한 좌표에 2가지의 데이터를
저장해야하는 상황이 발생된다. 물론 미설치 - 0, 기둥설치 - 1, 보설치 - 2, 둘다설치 - 3 이와 같이 표기하는 방법도 존재하지만,
이런 경우면 보드의 값을 접근할 때, 값이 무엇인지 확인하는 조건문을 수시로 걸어서 필터링을 해주게 되는 매우 복잡한 상황이
연출된다.
따라서 (n+1)*(n+1) 사이즈의 배열을 2개 만들어서, 하나는 기둥의 설치 여부, 다른 하나는 보의 설치 여부를 확인하는 보드를 만들면 더욱 계산을 편하게 할 수 있다.
우리가 빌드 프레임 배열에서 기둥과 보를 설치 또는 제거한다는 명령을 읽어들인다.
형식은 [x, y, a, b]와 같은 형태이고, 각각은 [x좌표, y좌표, 건출물종류, 설치또는제거] 를 나타낸다.
우리는 각각의 정보를 하나씩 불러와서 우선 설치하는 명령인지, 제거하는 명령인지를 구별한다.
만약 설치하는 명령이라면, 교점좌표와 건축물종류 데이터를 가지고 보드에 값을 갱신한다.
기둥을 설치하는 거라면 기둥배열에 값을 갱신하고, 보를 설치하는 경우라면 보배열에 값을 갱신한다.
이 때, 설치하기 전에 해당 좌표에 해당 건출물을 설치 할 수 있는지에 대한 판별이 필요하다.
이 부분은 외부로 따로 함수를 분리하여 사용하는 편이 좋다. 자주 사용되기 때문이다.
설치 판별함수는 기둥과 보를 설치하는 부분에서 갈리게 된다.
하나의 함수를 만들어도 좋고, 생각하기 편하게 2가지의 함수로 따로따로 만들어도 좋다.
기둥설치여부를 판별하는 함수는 대충이렇다.
여기서 두 번째의 경우와 세 번째의 경우가 어렵게 느껴질 것이다.
세 번째의 경우부터 보자면 현재 좌표에 보가 있다고 하면, 당연히 그 위에 기둥을 세울 수 있는 건 당연하다.
두 번째의 경우는 x축의 왼쪽으로 하나떨어졌다는 의미는, 가로축의 좌표가 하나 왼쪽을 떨어진 곳에 보가
설치 되었냐는 말이다. 이걸 왜 확인하냐면, 자신의 위치 기준으로 왼쪽 하나 떨어진 좌표에 보가 설치되어있으면,
보는 항상 오른쪽으로 설치되므로 자기 자신이 기둥을 세우려는 좌표까지 영향을 준다. 즉, 보가 설치되어있다면,
보 위에는 기둥이 설치가 가능하니까 확인해야하는 부분이다.
보의 설치여부를 판별하는 함수는 아래와 같다.
보의 설치여부 판별이 기둥보다는 약간 더 복잡하다. 보는 기둥에 비해 더 많은 규칙을 가지고 있으므로 당연한 결과이다.
먼저 보는 한쪽이라도 기둥위에 세워지면 무조건 설치가 가능하다. 첫 번째와 두 번째의 경우는 이를 판별한 것이다.
기둥은 현재 설치좌표보다 하나 아래 설치되므로, 현재좌표에서 y축 값을 1을 감산한 위치에서 봐야한다.
또한 보의 영향은 x축 방향으로 오른쪽 하나 이동한 위치까지이다. 따로 그 위치에서 y축으로 하나 아래 떨어진 부분에
기둥이 세워져있으면, 역시 한 쪽 부분을 기둥으로 지탱하고 있는 모양이 형성되므로, 보설치가 가능하다.
만약 기둥이 세워져있지 않다면, 보는 반드시 양쪽에 보끼리 연결되어있어야한다. x축이 0인걸 확인하는 이유는 왼쪽에
보를 설치할 수 있는 경우는 없기 때문이다. 반드시 False가 리턴된다. 그럼 반대로 물어보는 사람이 존재할 수 있다. 가장 끝
부분에도 보를 설치 할 수 없을 텐데, 왜 그 부분은 확인을 안하나요? 라고 말이다. 마지막 위치에는 문제의 규칙상 설치될
염려가 없기 때문이라고 대답할 수 있다. 네 번째 규칙을 보면 우리는 현재위치를 기준으로 x축으로 왼쪽 오른쪽을 탐색하여,
보가 양쪽에 둘 다 설치 되었는지를 확인해야한다. 5*5보드에 보가 설치되는 y축영역은 0~4까지 이다. 5는 영역밖이므로,
설치가 불가능하다. 자연스럽게 배제가 가능하지만, -1은 보드의 영역을 초과하므로(파이썬은 아닌가?...)저기서 x좌표의 값이
0인경우를 굳이 판별한다. 에러나면 곤란하다...
위의 함수를 만들 때, 기둥배열하고 보배열을 정확히 참조하여 만들도록 하자.
마지막 난관은 삭제판별이다.
이 부분은 많은 사람들이 난관을 겪고 있는 부분이된다.
이 문제를 빠르게 풀려면, 시간복잡도를 생각하지 않고 전체 검사를 하면 되긴한다.
전체검사를 선택한 경우라면, 보드에서 해당 값을 지운다음에,
나머지 값들을 다시 판별함수에 전부 넣어서 전부 True를 반환하는지를 확인하면 된다.
즉 이미 설치되어있는 구조물을 다시 그 자리에 설치해봄으로써, 조건에 문제가 없는지를 확인해본다.
만약, 효율성을 추구하는 분이라면, 삭제된 부분이 생김으로써 영향이 가는 부분 만을 검사하는 것이 좋은방법이다.
가장 효율적이지만, 시간이 많다면 한 번 해보는 것을 추천한다. 실제시험에서는 시간이 없으므로 첫 번째 방법을 추천한다.
효율적인 삭제 판별에는 2가지의 경우로 나누어서 볼 수 있다.
기둥을 삭제하는 경우와, 보를 삭제하는 두 가지의 경우이다. 너무 뻔해서 아마 다들 알고 있지 않을까 싶다.
먼저 기둥을 삭제하면, 어느 부분에 영향이 가는지 살펴보겠다.
기둥을 지운다고 해서, 기둥의 밑 부분에는 아무런 변화도 없다. 기둥의 밑 부분은 설치조건에만 해당되기 때문이다.
현재 지우려는 기둥 윗부분에 기둥이 존재한다면, 영향이 분명히 갈 것이다. 검사범위 1이다.
다음은, 기둥을 삭제함으로써 보에 영향이 가는지 알아보자. 삭제하려는 기둥 바로 위에 설치된 보가 영향이 갈 것이다.
밑의 기둥이 없어졌으므로, 지탱하고 있는 다른 무언가가 있는지 다시 확인해야 할 필요가 생긴다. 검사범위 2이다.
삭제 할 기둥은 바로 위의 보만 지지하는 것이 아니다. 왼쪽으로 하나 위로 하나 떨어진 위치에 설치된 보도 현재 기둥을
삭제함으로써 영향이 간다. 보의 끝 부분이 현재 삭제하려는 기둥에 지탱하는 경우다. 검사범위 3이다.
이렇게 기둥을 삭제 할 경우에는 총 3가지의 위치에서 변동이 일어나게 된다.
보를 삭제하는 경우를 알아보자, 보는 기둥보다 규칙이 까다로우므로 검사할 범위도 추가된다.
귀찮으니 간단하게 알아보자, 그림으로 그려서 확인하면 이해는 갈 것이다.
위와 같이 총 4 종류의 범위에 영향이 간다. 설치 규칙만 확실히 숙지하고 있다면, 이 정도 영향 범위는 손쉽게 생각해낼 수 있다.
확실한 것은 삭제 범위를 판별 할 때는 현재 설치 위치보다 아래의 부분은 볼 필요가 없다는 점이다.
애초부터 해당 위치를 삭제했다고, 아래 부분에 영향이 갔다면, 설치 조건에도 부합하지 않았을 것이다.
만약 판별에서 False가 한 번이라도 나오게 되면, 해당 기둥이나 보는 삭제하지 않는 선택을 한다.
모든 build_frame배열을 돌았다면, 기둥배열과 보배열의 값들을 전부 탐색하여, 답안을 추가한다.
x와 y를 0~n까지 탐색하면서, 기둥배열값을 먼저 확인하고, 보배열의 값을 확인하면서 답안을 추가한다면,
자연스럽게 정렬이 이루어질 것이다.
답안을 제출하면 마무리이다.
모두들 나이쓰한 하루 보내시고,
도움이 되셨으면 합니다.
만약 이해가 안가신다면, 제가 너무 어렵게 쓴 거니 저를 탓하세요... :)
친절한 해설 감사합니다:)
정성스럽게 작성해주셔서 감사합니다!!
자세한 설명 감사합니다 !