C++ 백준 17413번/10799번
by 너나나다 스택에 관한 문제들이다.
백준 17413번 www.acmicpc.net/problem/17413
17413번: 단어 뒤집기 2
문자열 S가 주어졌을 때, 이 문자열에서 단어만 뒤집으려고 한다. 먼저, 문자열 S는 아래와과 같은 규칙을 지킨다. 알파벳 소문자('a'-'z'), 숫자('0'-'9'), 공백(' '), 특수 문자('<', '>')로만 이루어져
www.acmicpc.net
문제 : 문자열 S가 주어졌을 때, 이 문자열에서 단어만 뒤집으려고 한다.
먼저, 문자열 S는 아래와 같은 규칙을 지킨다.
- 알파벳 소문자('a'-'z'), 숫자('0'-'9'), 공백(' '), 특수 문자('<', '>')로만 이루어져 있다.
- 문자열의 시작과 끝은 공백이 아니다.
- '<'와 '>'가 문자열에 있는 경우 번갈아가면서 등장하며, '<'이 먼저 등장한다. 또, 두 문자의 개수는 같다.
태그는 '<'로 시작해서 '>'로 끝나는 길이가 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
문제 : 여러 개의 쇠막대기를 레이저로 절단하려고 한다. 효율적인 작업을 위해서 쇠막대기를 아래에서 위로 겹쳐 놓고, 레이저를 위에서 수직으로 발사하여 쇠막대기들을 자른다. 쇠막대기와 레이저의 배치는 다음 조건을 만족한다.
- 쇠막대기는 자신보다 긴 쇠막대기 위에만 놓일 수 있다. - 쇠막대기를 다른 쇠막대기 위에 놓는 경우 완전히 포함되도록 놓되, 끝점은 겹치지 않도록 놓는다.
- 각 쇠막대기를 자르는 레이저는 적어도 하나 존재한다.
- 레이저는 어떤 쇠막대기의 양 끝점과도 겹치지 않는다.
아래 그림은 위 조건을 만족하는 예를 보여준다. 수평으로 그려진 굵은 실선은 쇠막대기이고, 점은 레이저의 위치, 수직으로 그려진 점선 화살표는 레이저의 발사 방향이다.
이러한 레이저와 쇠막대기의 배치는 다음과 같이 괄호를 이용하여 왼쪽부터 순서대로 표현할 수 있다.
- 레이저는 여는 괄호와 닫는 괄호의 인접한 쌍 ‘( ) ’으로 표현된다. 또한, 모든 ‘( ) ’는 반드시 레이저를 표현한다.
- 쇠막대기의 왼쪽 끝은 여는 괄호 ‘ ( ’로, 오른쪽 끝은 닫힌 괄호 ‘) ’로 표현된다.
위 예의 괄호 표현은 그림 위에 주어져 있다.
쇠막대기는 레이저에 의해 몇 개의 조각으로 잘리는데, 위 예에서 가장 위에 있는 두 개의 쇠막대기는 각각 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';
}
문제 이해만 하면 구현은 별로 어렵지 않은 문제인 거 같다!
'study > 알고리즘' 카테고리의 다른 글
C++ 알고리즘 소수구하기 - 에라토스테네스의 체 (0) | 2020.12.28 |
---|---|
C++ 알고리즘 나머지 연산/최대공약수/소수 (0) | 2020.12.28 |
C++ 자료구조 3 - 덱(deque) (0) | 2020.12.24 |
C++ 자료구조 2 - 큐(queue)/백준 1158번 (0) | 2020.12.24 |
C++ 자료구조 1 - 백준 1874번, 1406번 (0) | 2020.12.23 |
블로그의 정보
공부 기록
너나나