공부 기록

C++ 백준 17413번/10799번

by 너나나

다 스택에 관한 문제들이다.

백준 17413번 www.acmicpc.net/problem/17413

 

17413번: 단어 뒤집기 2

문자열 S가 주어졌을 때, 이 문자열에서 단어만 뒤집으려고 한다. 먼저, 문자열 S는 아래와과 같은 규칙을 지킨다. 알파벳 소문자('a'-'z'), 숫자('0'-'9'), 공백(' '), 특수 문자('<', '>')로만 이루어져

www.acmicpc.net

문제 : 문자열 S가 주어졌을 때, 이 문자열에서 단어만 뒤집으려고 한다.

먼저, 문자열 S는 아래와 같은 규칙을 지킨다.

  1. 알파벳 소문자('a'-'z'), 숫자('0'-'9'), 공백(' '), 특수 문자('<', '>')로만 이루어져 있다.
  2. 문자열의 시작과 끝은 공백이 아니다.
  3. '<'와 '>'가 문자열에 있는 경우 번갈아가면서 등장하며, '<'이 먼저 등장한다. 또, 두 문자의 개수는 같다.

태그는 '<'로 시작해서 '>'로 끝나는 길이가 3 이상인 부분 문자열이고, '<'와 '>' 사이에는 알파벳 소문자와 공백만 있다. 단어는 알파벳 소문자와 숫자로 이루어진 부분 문자열이고, 연속하는 두 단어는 공백 하나로 구분한다. 태그는 단어가 아니며, 태그와 단어 사이에는 공백이 없다.

 

예전에 풀었던 단어 뒤집기에서 진화했다. ( guiyum.tistory.com/2 여기 9093번)

단어들을 공백으로 구분하고 뒤집는데 <> 안에 있는 친구들은 뒤집지 않는다.

예를 들면 i am student는 i ma tneduts로 뒤집는데

i am <student>는 i ma <student>로 뒤집는 것이다.

#include<iostream>
#include<stack>
#include<string>
using namespace std;

void print(stack<char>& s) {
	while (!s.empty()) {
		cout << s.top();
		s.pop();
	}
}
int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(nullptr);
	string str;
	bool tag = false; // <>안에 들어있는 문자인지 알려준다
	getline(cin, str); // '\n'이 들어올때 까지 입력 받는다.
	stack<char> s;
	for (char ch : str) { //str의 문자 하나씩 스택에 넣어주기 위해서 for문 사용
		if (ch == '<') {
			print(s); // 얘 앞에 있는 애들도 하나의 단어라 일단 출력해줌
			tag = true;
			cout << ch;
		}
		else if (ch == '>') {
			tag = false;
			cout << ch;
		}
		else if (ch == ' ') {
			print(s);
			cout << ch; // 띄어쓰기
		}
		else if (tag) {
			cout << ch;
		}
		else {
			s.push(ch);
		}
	}
	print(s); // 마지막 단어는 공백으로 구분되는게 아니니까 마지막은 출력!
	cout << '\n';
	
	return 0;
}

 

백준 10799번 www.acmicpc.net/problem/10799

 

10799번: 쇠막대기

여러 개의 쇠막대기를 레이저로 절단하려고 한다. 효율적인 작업을 위해서 쇠막대기를 아래에서 위로 겹쳐 놓고, 레이저를 위에서 수직으로 발사하여 쇠막대기들을 자른다. 쇠막대기와 레이저

www.acmicpc.net

문제 : 여러 개의 쇠막대기를 레이저로 절단하려고 한다. 효율적인 작업을 위해서 쇠막대기를 아래에서 위로 겹쳐 놓고, 레이저를 위에서 수직으로 발사하여 쇠막대기들을 자른다. 쇠막대기와 레이저의 배치는 다음 조건을 만족한다.

  • 쇠막대기는 자신보다 긴 쇠막대기 위에만 놓일 수 있다. - 쇠막대기를 다른 쇠막대기 위에 놓는 경우 완전히 포함되도록 놓되, 끝점은 겹치지 않도록 놓는다.
  • 각 쇠막대기를 자르는 레이저는 적어도 하나 존재한다.
  • 레이저는 어떤 쇠막대기의 양 끝점과도 겹치지 않는다. 

아래 그림은 위 조건을 만족하는 예를 보여준다. 수평으로 그려진 굵은 실선은 쇠막대기이고, 점은 레이저의 위치, 수직으로 그려진 점선 화살표는 레이저의 발사 방향이다.

이러한 레이저와 쇠막대기의 배치는 다음과 같이 괄호를 이용하여 왼쪽부터 순서대로 표현할 수 있다.

  1. 레이저는 여는 괄호와 닫는 괄호의 인접한 쌍 ‘( ) ’으로 표현된다. 또한, 모든 ‘( ) ’는 반드시 레이저를 표현한다.
  2. 쇠막대기의 왼쪽 끝은 여는 괄호 ‘ ( ’로, 오른쪽 끝은 닫힌 괄호 ‘) ’로 표현된다. 

위 예의 괄호 표현은 그림 위에 주어져 있다.

쇠막대기는 레이저에 의해 몇 개의 조각으로 잘리는데, 위 예에서 가장 위에 있는 두 개의 쇠막대기는 각각 3개와 2개의 조각으로 잘리고, 이와 같은 방식으로 주어진 쇠막대기들은 총 17개의 조각으로 잘린다. 

쇠막대기와 레이저의 배치를 나타내는 괄호 표현이 주어졌을 때, 잘린 쇠막대기 조각의 총개수를 구하는 프로그램을 작성하시오.

 

얘도 예전에 풀었던 괄호 문제에서 진화했다!! (guiyum.tistory.com/2 여기에 9012번 문제)

문제를 또 풀어서 설명하면 여러 개 괄호들이 있는데 () 이렇게 바로 여는 괄호와 닫는 괄호가 붙어서 나오면 레이저이고 안 붙은 친구들은 하나의 쇠막대기를 만든다.

예를 들어 ((())) 이런 괄호들이 있으면 ((())) 가운데 인접해있는 여는 괄호 닫는 괄호는 레이저이고 ((())이 파란애들 둘이 쇠막대기 하나를 만들고 ((())) 초록색 둘이서 또 쇠막대기 하나를 만든다. 그래서 처음에 만들어진 쇠막대기는 두 개인데 레이저가 이 막대기들을 반으로 가른다.

이걸 스택으로 생각해보면

여는 괄호들을 담는 스택을 만들고 만약 여는 괄호랑 붙어서 나온 닫는 괄호가 있으면 얘는 이 다른 여는 괄호들이 만든 쇠막대기를 가르기 때문에 이 쇠막대기들의 개수만큼 이 더 생긴다. (3개의 쇠막대기를 레이저 하나가 지나가면 이 쇠막대기들이 잘려 3개가 더 생긴다. 만약 이 쇠막대기들이 좀 긴 친구들이라 레이저 하나가 더 지나가게 된다면 3 + 3 + 3 개수가 된다.)

#include<iostream>
#include<stack>
#include<string>
using namespace std;

int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(nullptr);
	stack<char> s;
	string input;
	int sum = 0;
	cin >> input;
	for(int i = 0; i <input.size(); i++)
	{
		if (input[i] == '(')
			s.push(input[i]); // 여는 괄호면 stack에 넣는다
		else if (input[i] == ')') {
			if (input[i-1] == '(') {
				s.pop();
				sum += s.size(); // 레이저가 지나가면 stack에 있는 쇠막대기들이 잘려져 원래 있던 쇠막대기 숫자만큼 갯수가 늘어난다.
			}
			else {
				sum++; // 연달아 나온게 아니라면 ) 는 쇠막대기의 끝을 뜻함!!
				s.pop(); // 이 쇠막대기는 끝났으니까 pop해준다
			}
		}
	}
	cout << sum << '\n';
}

문제 이해만 하면 구현은 별로 어렵지 않은 문제인 거 같다!

 

블로그의 정보

공부 기록

너나나

활동하기