[알고리즘][구름] 장마

Jaino Song·2024년 6월 12일

알고리즘

목록 보기
4/7

문제

구름이가 사는 마을에는 1번 집부터 번 집까지 총 V개의 집이 순서대로 세워져 있다.
마을의 땅 높이는 제각각이어서, 번째 집의 땅 높이는 K; 이다. 땅 높이의 기준은 해수면이기 때문에, 해수면보다 낮은 위치에 집이 있다면 높이가 음수일 수도 있다.
장마가 시작되면 MM 일 동안 멈추지 않고 비가 온다. 장마가 시작된 지 i일이 되는 날에는
5; 번 집이 있는 위치부터 ex번 집이 있는 위치까지 비가 내린다. 어떤 집에 비가 내리면 그 집에 쌓인 물의 높이가 1만큼 증가한다. 한 번 쌓인 물은 배수 시스템이 작동하기 전까지는 빠지지 않는다.
배수 시스템은 장마가 시작된 지 3의 배수가 되는 날마다, 비가 내리고 난 뒤 작동한다.
배수 시스템은 작동 날짜를 기준으로 2일 이내에 비가 내린 위치에서만 작동한다. 예를 들어, 장마가 시작되고 9일째에 작동하는 배수 시스템은 7, 8, 9일 째에 비가 내린 위치에서만 작동한다. 배수 시스템이 작동하면 그 집에 쌓인 물의 높이가 1만큼 감소한다.
장마가 지나간 뒤, 마을의 모든 땅 높이는 그 땅에 쌓였던 물의 높이만큼 증가한다.
구름이는 1번 집부터 번 집까지의 땅 높이를 다시 조사하려고 한다. 구름이를 도와 변한 땅 높이를 구해보자.

입력

첫째 줄에 집의 개수 N과 장마 기간 M이 공백을 두고 주어진다.
둘째 줄에 마을의 땅 높이 k1, k2,..., kN이 공백을 두고 주어진다.
다음 M 개의 줄에는 si, ei가 공백을 두고 주어진다. 장마가 시작된 지 i일이 되는 날에는 5; 번 집이 있는 위치부터 번 집이 있는 위치까지 비가 내렸다는 의미이다.
• 1 ≤ N ≤ 1,000
• 1 ≤ M ≤ 100,000
• -100,000 ≤ ki ≤ 100,000
• 1 ≤ si ≤ ei ≤ N
• 입력에서 주어지는 모든 수는 정수이다.

출력

장마가 끝난 뒤, 1번 집부터 번 집까지의 땅 높이를 한 줄에 하나씩 출력한다.

예시 1

입력

5 5
-1 0 1 0 2
1 1
2 2
3 3
4 5
4 5

출력

-1 0 1 2 4

예시 2

입력

5 7
0 0 0 0 0
1 5
1 5
1 5
1 5
1 5
1 5
1 2

출력

5 5 4 4 4

풀이

const readline = require('readline');

(async () => {
    const rl = readline.createInterface({ input: process.stdin });

    let input = [];
    for await (const line of rl) {
		    // 입력의 각 라인을 불러오고, trim()을 통해 시작과 끝에 있을 수 있는 공백을 삭제하고 input 배열에 push 한다
        input.push(line.trim());
    }
    rl.close();
		
		// input 배열의 0 자리에 있는 두 숫자를 destructuring 해서 지정한다.
    const [houseNum, rainDays] = input[0].split(' ').map(Number); // houseNum = 5, rainDays = 5
    // input 배열의 1 자리에 있는 각 집의 높이가 저장된 요소를 불러와서 숫자로 띄어쓰기를 기준으로 나눠서 배열 요소로 집어 넣는다.
    let houseHeight = input[1].split(' ').map(Number); // [-1, 0, 1, 0, 2] 
    // input 배열의 첫 요소를 없애고, 비가 온 집들의 위치만 넣는다.
    let forecast = input.slice(2); // forecast = ['1 1', '2 2',... '4 5']

    let waterHeight = Array(houseNum).fill(0); // waterHeight = [0, 0, 0, 0, 0]
    // recentRain 안에 set을 사용해서 당일을 포함해서 최근 3일간 비가 온 집의 인덱스를 set에 추가한다. 이 set은 배수 시스템이 작동하면 clear된다.
    let recentRain = new Set();

		// 비가 온 집의 물 높이를 계산
		// 먼저 비가 온 날을 기준
    for (let day = 0; day < rainDays; day++) {
		    // forecast 배열에 있는 각 비가 온 날의 비가 온 시작 집과 끝 집을 destructuring으로 가져온다.
        let [startPosition, endPosition] = forecast[day].split(' ').map(Number); // forecast[0] 일때 startPosition = 1, endPostion = 1
        startPosition -= 1; // 배열의 위치는 0 부터 시작하기에 0으로 부터 시작하는 걸로 계산
        endPosition -= 1; // 배열의 위치는 0 부터 시작하기에 0으로 부터 시작하는 걸로 계산
				
				// 시작 집부터 끝 집까지 물 높이와 비가 온 날을 추가해준다.
        for (let i = startPosition; i <= endPosition; i++) {
		        // 물 높이 추가
            waterHeight[i]++;
            // 비가 온 집의 인덱스를 set에 추가한다.
            recentRain.add(i);
        }
				// 3번 째 비오는 날 마다 배수 시스템 작동
        if ((day + 1) % 3 === 0) {
		        // set 안에 저장된 집들을 하나씩 불러온다.
            for (let j of recentRain) {
		            // 물 높이를 1씩 줄여주고, 0보다 작지 않게 해준다.
                waterHeight[j] = Math.max(0, waterHeight[j] - 1);
            }
            // set을 clear하여 다음 비오는 사이클을 위해 비워준다.
            recentRain.clear();
        }
    }
		
		// 각 집마다 물 높으만큼 땅 높이를 높여 준다.
    for (let i = 0; i < houseHeight.length; i++) {
        houseHeight[i] += waterHeight[i];
    }
		// 배열로 저장된 땅 높이를 하나의 String으로 합쳐서 반환한다.
    console.log(houseHeight.join(' '));

    process.exit();
})();
profile
하루하루 목표를 향해 나아가야지

0개의 댓글