BOJ : 백준 10799 쇠막대기(JAVA)

백준 10799 쇠막대기 자바 풀이 💡
알고리즘자료구조
avatar
2025.04.27
·
8 min read

문제

시간 제한 : 1초, 메모리 제한 : 256MB
여러 개의 쇠막대기를 레이저로 절단하려고 한다. 효율적인 작업을 위해서 쇠막대기를 아래에서 위로 겹쳐 놓고, 레이저를 위에서 수직으로 발사하여 쇠막대기들을 자른다. 쇠막대기와 레이저의 배치는 다음 조건을 만족한다.
쇠막대기는 자신보다 긴 쇠막대기 위에만 놓일 수 있다. - 쇠막대기를 다른 쇠막대기 위에 놓는 경우 완전히 포함되도록 놓되, 끝점은 겹치지 않도록 놓는다.
각 쇠막대기를 자르는 레이저는 적어도 하나 존재한다.
레이저는 어떤 쇠막대기의 양 끝점과도 겹치지 않는다.
아래 그림은 위 조건을 만족하는 예를 보여준다. 수평으로 그려진 굵은 실선은 쇠막대기이고, 점은 레이저의 위치, 수직으로 그려진 점선 화살표는 레이저의 발사 방향이다.

5605


이러한 레이저와 쇠막대기의 배치는 다음과 같이 괄호를 이용하여 왼쪽부터 순서대로 표현할 수 있다.
레이저는 여는 괄호와 닫는 괄호의 인접한 쌍 ‘( ) ’ 으로 표현된다. 또한, 모든 ‘( ) ’는 반드시 레이저를 표현한다.
쇠막대기의 왼쪽 끝은 여는 괄호 ‘ ( ’ 로, 오른쪽 끝은 닫힌 괄호 ‘) ’ 로 표현된다.
위 예의 괄호 표현은 그림 위에 주어져 있다.
쇠막대기는 레이저에 의해 몇 개의 조각으로 잘려지는데, 위 예에서 가장 위에 있는 두 개의 쇠막대기는 각각 3개와 2개의 조각으로 잘려지고, 이와 같은 방식으로 주어진 쇠막대기들은 총 17개의 조각으로 잘려진다.
쇠막대기와 레이저의 배치를 나타내는 괄호 표현이 주어졌을 때, 잘려진 쇠막대기 조각의 총 개수를 구하는 프로그램을 작성하시오.

입력
쇠막대기와 레이저의 배치를 나타내는 괄호 표현이 한 줄로 나온다.
((()()()).. 이런 식으로!

출력
잘려진 조각의 총 개수

()는 무조건 레이저, (....)가 쇠막대기에 해당한다.
((())) 여기서 굵게 표시된 부분만 쇠막대기인 것이다.

풀이

스택을 이해할 때 풀어봤던 문제에서 비슷한 유형을 봤던 기억이 났다!
( 들을 계속 stack에 넣다가 ) 나오면 ( 를 빼는 걸로 괄호가 몇 개나 완성되었는지 알 수 있는 문제였는데, 여기에 비슷하게 적용할 수 있을 것 같아 이러한 자료구조를 사용하기로 했다.

그러면 일단 레이저와 철몽둥이 개수가 몇 개인지는 셀 수 있을 것 같다.

예시 1.을 예시로 들자면
인풋은 다음과 같다 : ()(((()())(())()))(())
() => 레이저
(((( + ) => 3개
(((( + ) => 3개
((( + ) (레이저 아님) => 1개
(((( + ) => 3개
((( + ) (레이저 아님) => 1개
((( + ) (레이저 아님) => 2개
(( + ) (레이저 아님) => 1개
( + ) (레이저 아님) => 1개
(( + ) => 1개
( + ) (레이저 아님) => 1개
=> 도합 17!

레이저가 아닐 때는 그냥 +1
레이저이면 stack 안에 든 (의 개수를 세어 추가하면 될 것 같다!

import java.util.*;
import java.io.*;

public class Main {

	public static void main(String[] args) throws IOException {

		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
		
		Stack<Character> stack = new Stack<>();
		String arrangement = br.readLine();
		int res = 0;
		
        // 1에서부터 시작할 것이므로 일단 ( 추가하고 시작
		stack.add('(');
        
		for(int i=1; i<arrangement.length(); i++) {
			if(arrangement.charAt(i) == '(') {
				stack.push('(');
			} else {
            	// )가 들어온 경우 일단 queue에서 하나 빼고 시작
				stack.pop();
				
				// 바로 전 문자가 ( 이다 = 레이저인 상황
				if(arrangement.charAt(i-1) == '(') {
					res += stack.size();
				} 
                // 바로 전 문자가 ( 가 아니다 = 레이저가 아닌 상황
                else { 
					res += 1;
				}
				
			}
		}
		
		bw.write(String.valueOf(res));
		bw.flush();
		bw.close();

	}

}

위처럼 stack을 사용해도 되지만... 사실 앞의 괄호가 닫혔는지 뒤의 괄호가 닫혔는지는 상관이 없으므로 queue를 사용해서 풀어도 진행될 것 같아 한 번 진행해보았다.

import java.util.*;
import java.io.*;

public class Main {

	public static void main(String[] args) throws IOException {

		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
		
		Queue<Character> queue = new LinkedList<>();
		String arrangement = br.readLine();
		int res = 0;
		
        // 1에서부터 시작할 것이므로 일단 ( 추가하고 시작
		queue.add('(');
        
		for(int i=1; i<arrangement.length(); i++) {
			if(arrangement.charAt(i) == '(') {
				queue.add('(');
			} else {
            	// )가 들어온 경우 일단 queue에서 하나 빼고 시작
				queue.poll();
				
				// 바로 전 문자가 ( 이다 = 레이저인 상황
				if(arrangement.charAt(i-1) == '(') {
					res += queue.size();
				} 
                // 바로 전 문자가 ( 가 아니다 = 레이저가 아닌 상황
                else { 
					res += 1;
				}
				
			}
		}
		
		bw.write(String.valueOf(res));
		bw.flush();
		bw.close();

	}

}
5604

굿!ㅎㅎ


문제를 풀며

Queue는 FIFO(선입선출), Stack은 LIFO(후입선출)이다.

예전에 패스트푸드점 알바를 잠깐 했었는데 매니저님한테서 선입선출이라는 단어를 귀에 딱지가 앉도록 들었었다.. 직접 재료들을 옮겨가며.. 선입선출을 구현했었는데 ㅋㅋ
이후 자료구조 수업을 수강할 때 큐를 배우며 선입선출이라는 단어가 나와 놀랐던 기억이 있다. 그 덕분에 큐와 스택은 헷갈리지 않게 됐다.
지금 이 일을 되새겨보니 여러 가지를 다양하게, 열심히 경험해보면 늘 어딘가에는 도움이 되는 것 같다는 생각이 든다. 오늘도 파이팅해야겠다 🤓







- 컬렉션 아티클