
도시에서 태양이 질 때에 보이는 건물들의 윤곽을 스카이라인이라고 한다. 스카이라인만을 보고서 도시에 세워진 건물이 몇 채인지 알아 낼 수 있을까? 건물은 모두 직사각형 모양으로 밋밋하게 생겼다고 가정한다.
정확히 건물이 몇 개 있는지 알아내는 것은 대부분의 경우에 불가능하고, 건물이 최소한 몇 채 인지 알아내는 것은 가능해 보인다. 이를 알아내는 프로그램을 작성해 보자.
첫째 줄에 n이 주어진다. (1 ≤ n ≤ 50,000) 다음 n개의 줄에는 왼쪽부터 스카이라인을 보아 갈 때 스카이라인의 고도가 바뀌는 지점의 좌표 x와 y가 주어진다.
(1 ≤ x ≤ 1,000,000. 0 ≤ y ≤ 500,000) 첫 번째 지점의 x좌표는 항상 1이다.
건물의 고도가 바뀌는 좌표가 주어졌을 때 해당 스카이라인을 형성할 수 있는 건물 개수의 하한을 찾는 문제이다.
해당 문제에서 2가지의 조건을 이용해 문제를 해결 할 수 있다.
먼저 문제에서 건물은 모두 직사각형 모양으로 밋밋하게 생겼다고 하였으므로 높이가 다를 경우에는 다른 건물이라는 첫 번째 조건을 추론할 수 있다.
두 번째 조건을 추론하기 위해 예를 들어 다음과 같은 스카이라인이 존재한다고 가정하면
........... ...XXXXX... ...XXXXX... ...XXXXX...
아래와 같은 구성으로 5채의 건물이 존재 할 수 있다.
........... ...12345... ...12345... ...12345...
구성은 매번 달라질 수 있으므로 정확히 몇 채의 건물이 존재하는지 알아내는 것은 불가능하다.
하지만 해당 스카이라인이 5층의 높이를 가진 하나의 건물이라 가정하면 건물 개수의 하한은 1채가 된다.
따라서 높이가 같은 인접 건물은 하나의 건물로 취급하면 된다는 두 번째 조건이 도출된다.
도출된 두 가지의 조건을 만족하는 코드를 구현하기 위해서는 스택을 이용해 고도의 변화가 생길 때 마다 새로운 건물인지 이미 스택에 존재하는 건물인지 판별하면 된다.
스택을 이용해 위의 조건을 만족하는 로직을 생각해 보면 다음과 같다.
스택의 마지막에 존재하는 고도를 peek, 새로 추가하려는 고도를 nextY라 하였을 때
해당 로직을 코드로 구현하면 문제를 해결 할 수 있다.
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
Stack<Integer> stk = new Stack<>();
// 고도 변화 지점의 개수 입력
int N = Integer.parseInt(br.readLine());
int tower = 0; // 건물 개수 저장할 변수
for (int i = 0; i < N; i++) {
String[] s = br.readLine().split(" ");
int nextY = Integer.parseInt(s[1]); // 스택에 추가할 고도 입력
// 건물의 끝점인 경우 pop 및 개수 증가
while(!stk.isEmpty() && stk.peek() > nextY) {
stk.pop();
tower++;
}
if(nextY == 0) stk.clear(); // 고도가 0이면 건물 남은 건물 없음
else if(stk.isEmpty() || stk.peek() < nextY) stk.push(nextY); // nextY != 0이고 스택 비었거나, 건물의 시작점일 경우 스택에 추가
}
// 건물 개수와 스택에 남은(끝점이 명시되지 않은) 건물의 합
System.out.println(tower + stk.size());
}
}
#include <iostream>
#include <stack>
#define fastio ios_base::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr)
#define endl '\n'
using namespace std;
int main() {
fastio;
stack<int> stk;
// 고도 변화 지점의 개수 입력
int N;
cin >> N;
int tower = 0; // 건물 개수 저장할 변수
for (int i = 0; i < N; i++) {
int nextX, nextY;
cin >> nextX >> nextY; // 스택에 추가할 고도 입력
// 건물의 끝점인 경우 pop 및 개수 증가
while(!stk.empty() && stk.top() > nextY) {
stk.pop();
tower++;
}
if(nextY == 0) {
// 고도가 0이면 건물 남은 건물 없음
while(!stk.empty()) stk.pop();
} else if(stk.empty() || stk.top() < nextY){
// nextY != 0이고 스택 비었거나, 건물의 시작점일 경우 스택에 추가
stk.push(nextY);
}
}
// 건물 개수와 스택에 남은(끝점이 명시되지 않은) 건물의 합
cout << tower + stk.size() << endl;
return 0;
}
import java.util.*;
fun main(args: Array<String>) {
var stk = Stack<Int>()
// 고도 변화 지점의 개수 입력
var N = readLine()!!.toInt()
var tower = 0 // 건물 개수 저장할 변수
for (i in 0 until N) {
var info = readLine()!!.split(" ")
var nextY = info[1].toInt() // 스택에 추가할 고도 입력
// 건물의 끝점일 경우 pop 및 개수 증가
while (stk.isNotEmpty() && stk.peek() > nextY) {
stk.pop()
tower += 1
}
if (nextY == 0) {
// 고도가 0이면 남은 건물 없음
stk.clear()
} else if (stk.isEmpty() || stk.peek() < nextY) {
// nextY != 0이고 스택 비었거나, 건물의 시작점일 경우 스택에 추가
stk.push(nextY)
}
}
// 건물 개수와 스택에 남은(끝점이 명시되지 않은) 건물의 합
print(tower + stk.size)
}
from sys import stdin
def main():
stk = []
# 고도 변화 지점의 개수 입력
N = int(stdin.readline())
tower = 0 # 건물 개수 저장할 변수
for i in range(N):
info = stdin.readline().split(' ')
nextY = int(info[1]) # 스택에 추가할 고도 입력
# 건물의 끝점일 경우 pop 및 개수 증가
while stk and stk[-1] > nextY:
stk.pop()
tower += 1
if nextY == 0:
# 고도가 0이면 남은 건물 없음
stk.clear()
elif not stk or stk[-1] < nextY:
# nextY != 0이고 스택 비었거나, 건물의 시작점일 경우 스택에 추가
stk.append(nextY)
# 건물 개수와 스택에 남은(끝점이 명시되지 않은) 건물의 합
print(tower + len(stk))
if __name__ == "__main__":
main()
import Foundation
func main() {
var stk = Array<Int>()
// 고도 변화 지점의 개수 입력
var N = Int(readLine()!)!
var tower = 0 // 건물 개수 저장할 변수
for i in 0..<N {
var info = readLine()!.split(separator: " ")
var nextY = Int(info[1])! // 스택에 추가할 고도 입력
// 건물의 끝점일 경우 pop 및 개수 증가
while !stk.isEmpty && stk.last! > nextY {
stk.popLast()
tower += 1
}
if nextY == 0 {
// 고도가 0이면 남은 건물 없음
stk.removeAll()
} else if stk.isEmpty || stk.last! < nextY {
// nextY != 0이고 스택 비었거나, 건물의 시작점일 경우 스택에 추가
stk.append(nextY)
}
}
// 건물 개수와 스택에 남은(끝점이 명시되지 않은) 건물의 합
print(tower + stk.count)
}
main()
