스택 (stack)은 기본적인 자료구조 중 하나로, 컴퓨터 프로그램을 작성할 때 자주 이용되는 개념이다. 스택은 자료를 넣는 (push) 입구와 자료를 뽑는 (pop) 입구가 같아 제일 나중에 들어간 자료가 제일 먼저 나오는 (LIFO, Last in First out) 특성을 가지고 있다.

1부터 n까지의 수를 스택에 넣었다가 뽑아 늘어놓음으로써, 하나의 수열을 만들 수 있다. 이때, 스택에 push하는 순서는 반드시 오름차순을 지키도록 한다고 하자. 임의의 수열이 주어졌을 때 스택을 이용해 그 수열을 만들 수 있는지 없는지, 있다면 어떤 순서로 push와 pop 연산을 수행해야 하는지를 알아낼 수 있다. 이를 계산하는 프로그램을 작성하라.

 

입력

첫 줄에 n (1 ≤ n ≤ 100,000)이 주어진다. 둘째 줄부터 n개의 줄에는 수열을 이루는 1이상 n이하의 정수가 하나씩 순서대로 주어진다. 물론 같은 정수가 두 번 나오는 일은 없다.

 

 

출력

입력된 수열을 만들기 위해 필요한 연산을 한 줄에 한 개씩 출력한다. push연산은 +로, pop 연산은 -로 표현하도록 한다. 불가능한 경우 NO를 출력한다.

 

 

코드

import sys
input = sys.stdin.readline

n = int(input())
stack = []
cnt = 1
answer = []
flag = True

for i in range(n):
    num = int(input())
    while cnt <= num:
        stack.append(cnt)
        answer.append("+")
        cnt += 1
    
    if stack[-1] == num:
        stack.pop()
        answer.append("-")
    
    else:
        flag == False
        break

if flag ==  False:
    print("NO")
else:
    for i in answer:
        print(i)
스택에 수를 push 할 때는 반드시 오름차순으로만 push할 수 있다.
4를 push하기 위해서는 1~3까지를 모두 push하고난 후에 할 수 있다.
이런 식으로 스택에 push를 하다가 입력한 수열에 맞게 pop을 해야한다.
 
n = 8 일 때 스택에는 1, 2, 3, 4, 5, 6, 7, 8 순서대로 push를 해야 한다.
주어진 입력 수열이 4, 3, 6, 8, 7, 5, 2, 1 이라고 해보면,
 
첫번째로 4를 pop 해야 한다.
그러기 위해서는 스택에 1~4를 쌓아야 하고 그 후에 4를 pop해야 한다.
4를 pop하고 나면 스택에는 1, 2, 3이 남기에 별도의 과정 없이 바로 3을 pop해주면 된다.
그 다음으로 6을 pop해야 하기 때문에 5, 6을 쌓고 난 뒤 6을 pop 해준다.
 
"NO" 가 출력되는 경우:
스택에서 pop할 숫자가 입력한 숫자가 아닐 때
스택에 [1,2,3,4]가 남아있고 4가 아닌 3을 pop해야 한다면
3을 꺼내기 위해 4를 pop해야 한다.
그렇게 되면 더 이상 pop한 수들의 수열이 정답과 같을 수 없게 된다.

'Algorithm' 카테고리의 다른 글

[백준] 6603 로또 / python  (0) 2024.05.03
[백준] 11279 최대 힙 / python  (4) 2024.05.01
[백준] 11724 연결 요소의 개수 / python  (0) 2024.04.28
[백준] 1931 회의실 배정 / python  (1) 2024.04.26
[백준] 2xn 타일링 / python  (0) 2024.04.24

방향 없는 그래프가 주어졌을 때, 연결 요소 (Connected Component)의 개수를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 정점의 개수 N과 간선의 개수 M이 주어진다. (1 ≤ N ≤ 1,000, 0 ≤ M ≤ N×(N-1)/2) 둘째 줄부터 M개의 줄에 간선의 양 끝점 u와 v가 주어진다. (1 ≤ u, v ≤ N, u ≠ v) 같은 간선은 한 번만 주어진다.

출력

첫째 줄에 연결 요소의 개수를 출력한다.

 

코드

import sys
sys.setrecursionlimit(10**6)
input = sys.stdin.readline

N, M = map(int, input().split())
graph = [[] for _ in range(N+1)]
visited = [False]*(N+1)

for _ in range(M):
    a, b = map(int, input().split())
    graph[a].append(b)
    graph[b].append(a)

cnt = 0

def dfs(graph, v, visited):
    visited[v] = True
    for i in graph[v]:
        if not visited[i]:
            dfs(graph, i, visited)

for i in range(1, N+1):
    if not visited[i]:
        dfs(graph, i, visited)
        cnt += 1

print(cnt)

 

처음에는 최대로 연결되는 개수라고 이해를 했는데

이 문제에서 말하는 연결 요소는 연결되어 있는 그래프의 개수 나 영역의 개수였다.

DFS/BFS를 한 번 수행했을 때 방문되는 모든 노드를 묶어서 하나의 연결 요소라고 할 수 있다.

따라서 DFS/BFS가 수행되는 횟수가 연결 요소의 개수가 된다.

 

모든 노드를 순차적으로 방문하면서 아직 방문되지 않은 노드에 대해서

DFS/BFS를 실행하는 과정이 for문이다.

DFS/BFS가 한 번 끝날 때마다 cnt+1을 하게 되면 연결 요소의 개수를 구할 수 있다.

 

 

 

처음에 런타임 에러 (RecuresionError)가 떴다.

RecursionError는 재귀와 관련된 에러이다. 가장 많이 발생하는 이유는 파이썬이 정한 최대 재귀 깊이보다 재귀의 깊이가 더 깊어질 때이다.

파이썬이 정한 최대 깊이는 sys.getrecursionlimit()을 통해 확인할 수 있다.

백준의 채점 서버에서 이 값은 1000으로 되어 있다.

파이썬이 정한 최대 재귀 깊이를 변경하여 에러를 해결하였다.

sys.setrecursionlimit(10**6)

이 함수를 사용하면 소스의 최대 재귀 깊이를 1,000,000 정도로 크게 설정할 수 있다.

 

 

1931번: 회의실 배정

(1,4), (5,7), (8,11), (12,14) 를 이용할 수 있다.

www.acmicpc.net

한 개의 회의실이 있는데 이를 사용하고자 하는 N개의 회의에 대하여 회의실 사용표를 만들려고 한다. 각 회의 I에 대해 시작시간과 끝나는 시간이 주어져 있고, 각 회의가 겹치지 않게 하면서 회의실을 사용할 수 있는 회의의 최대 개수를 찾아보자. 단, 회의는 한번 시작하면 중간에 중단될 수 없으며 한 회의가 끝나는 것과 동시에 다음 회의가 시작될 수 있다. 회의의 시작시간과 끝나는 시간이 같을 수도 있다. 이 경우에는 시작하자마자 끝나는 것으로 생각하면 된다.

 

 

입력

첫째 줄에 회의의 수 N(1 ≤ N ≤ 100,000)이 주어진다. 둘째 줄부터 N+1 줄까지 각 회의의 정보가 주어지는데 이것은 공백을 사이에 두고 회의의 시작시간과 끝나는 시간이 주어진다. 시작 시간과 끝나는 시간은 231-1보다 작거나 같은 자연수 또는 0이다.

 

 

출력

첫째 줄에 최대 사용할 수 있는 회의의 최대 개수를 출력한다.

 

코드

import sys
input = sys.stdin.readline

n = int(input())
endPoint = 0
answer = 0
lectures = []

for i in range(n):
    a, b = map(int, input().split())
    lectures.append([a,b])

lectures.sort(key = lambda x: (x[1], x[0]))

for start, end in lectures:
    if endPoint <= start:
        answer += 1
        endPoint = end
print(answer)

 

끝나는 시간을 기준으로 배열을 정렬하고

현재 채택된 강의가 끝나는 시간 <= 그 다음 회의 시작 시간 인지를 검사한 후

조건을 만족하면 강의를 추가하고 끝나는 시간을 갱신하도록 구현하였다.

 

2차원 배열 정렬

* 첫 번째 값으로 정렬하기

array.sort(key=lambda x:x[0])

 

x:x[0] 으로 0번째 즉 배열에서 첫번째 인덱스에 대해서 정렬시켰다.

여기까지만 하면 0번째 인덱스에 대해서 오름차순 정렬이 되지만

동일한 0번째 인덱스를 가진 1번째 인덱스에 대해서는 정렬이 되지 않는다.

둘 다 오름차순 정렬이 되길 원한다면,

array.sort(key=lambda x: (x[0], x[1]))

 

요렇게 해줘야 함

 

*두 번째 값으로 정렬하기

x: () 괄호 안에 튜플 형식으로 집어넣는다.

- 를 앞에 붙이면 역으로 즉 내림차순으로 정렬시킬 수 있다.

array.sort(key=lambda x: (-x[1], x[0]))

 

요렇게 하면 첫번째 인덱스 요소들에 대해 내림차순으로 정렬하고,

동일한 첫번째 인덱스를 가진 요소들에 대해서는

0번째 요소들을 기준으로 오름차순으로 정렬한다.

 


 

마침 동아리 과제에서 C#으로 실버1 이상 문제 푸는 게 있어서 C#으로도 풀어봤다.

using System;

class Program
{
    static void Main(string[] args)
    {
        int n = int.Parse(Console.ReadLine());
        int endPoint = 0;
        int answer = 0;
        int[][] lectures = new int[n][];

        for (int i = 0; i < n; i++)
        {
            string[] input = Console.ReadLine().Split();
            int a = int.Parse(input[0]);
            int b = int.Parse(input[1]);
            lectures[i] = new int[] { a, b };
        }

        Array.Sort(lectures, (x, y) => {
            if (x[1] == y[1]) return x[0].CompareTo(y[0]);
            return x[1].CompareTo(y[1]);
        });

        foreach (int[] lecture in lectures)
        {
            int start = lecture[0];
            int end = lecture[1];
            if (endPoint <= start)
            {
                answer++;
                endPoint = end;
            }
        }
        Console.WriteLine(answer);
    }
}
 

11726번: 2×n 타일링

2×n 크기의 직사각형을 1×2, 2×1 타일로 채우는 방법의 수를 구하는 프로그램을 작성하시오. 아래 그림은 2×5 크기의 직사각형을 채운 한 가지 방법의 예이다.

www.acmicpc.net

2×n 크기의 직사각형을 1×2, 2×1 타일로 채우는 방법의 수를 구하는 프로그램을 작성하시오.

아래 그림은 2×5 크기의 직사각형을 채운 한 가지 방법의 예이다.

 

입력

첫째 줄에 n이 주어진다. (1 ≤ n ≤ 1,000)

 

출력

첫째 줄에 2×n 크기의 직사각형을 채우는 방법의 수를 10,007로 나눈 나머지를 출력한다.

 

코드

import sys
input = sys.stdin.readline

n = int(input())
solution = [0]*(n+1)

if n == 1:
    print(1)
elif n == 2:
    print(2)
else:
    solution[1] = 1
    solution[2] = 2
    for i in range(3, n+1):
        solution[i] = (solution[i-1] + solution[i-2]) % 10007
    print(solution[n])

 

2 x N 크기의 직사각형을 채울 수 있는 방법의 수는

2 x ( N-2 ) 크기의 직사각형을 채우는 경우의 수에 1 x 2 크기의 직사각형 2개를 붙이는 경우

+

2 x ( N-1 ) 크기의 직사각형을 채우는 경우의 수에 2 x 1 크기의 직사각형 1개를 붙이는 경우

이다.

 

 

9375번: 패션왕 신해빈

첫 번째 테스트 케이스는 headgear에 해당하는 의상이 hat, turban이며 eyewear에 해당하는 의상이 sunglasses이므로   (hat), (turban), (sunglasses), (hat,sunglasses), (turban,sunglasses)로 총 5가지 이다.

www.acmicpc.net

해빈이는 패션에 매우 민감해서 한번 입었던 옷들의 조합을 절대 다시 입지 않는다. 예를 들어 오늘 해빈이가 안경, 코트, 상의, 신발을 입었다면, 다음날은 바지를 추가로 입거나 안경대신 렌즈를 착용하거나 해야한다. 해빈이가 가진 의상들이 주어졌을때 과연 해빈이는 알몸이 아닌 상태로 며칠동안 밖에 돌아다닐 수 있을까?

 

입력

첫째 줄에 테스트 케이스가 주어진다. 테스트 케이스는 최대 100이다.

  • 각 테스트 케이스의 첫째 줄에는 해빈이가 가진 의상의 수 n(0 ≤ n ≤ 30)이 주어진다.
  • 다음 n개에는 해빈이가 가진 의상의 이름과 의상의 종류가 공백으로 구분되어 주어진다. 같은 종류의 의상은 하나만 입을 수 있다.

모든 문자열은 1이상 20이하의 알파벳 소문자로 이루어져있으며 같은 이름을 가진 의상은 존재하지 않는다.

 

출력

각 테스트 케이스에 대해 해빈이가 알몸이 아닌 상태로 의상을 입을 수 있는 경우를 출력하시오.

 

코드

import sys
from collections import Counter
input = sys.stdin.readline

n = int(input())
for _ in range(n):
    k = int(input())
    arr = []
    result = 1
    for _ in range(k):
        item, type = input().split()
        arr.append(type)
    cnt = Counter(arr)
    for item in cnt:
        result *= (cnt[item]+1)
    print(result-1)

 

의상의 이름과 종류를 입력 받는다.

사실 의상의 이름은 중요하지 않고 종류에 따라 개수를 세는 것이 더 중요하다.

따라서 입력을 받은 후 의상의 종류만 배열에 따로 저장하였고,

개수를 세기 위해 입력을 저장해놓은 배열을 다시 Counter함수에 입력하였다.

 

경우의 수는

의상마다

(의상의 종류의 개수 + 1(안 입는 것)) 의 경우의 수를 곱하고

최종적으로 아무것도 입지 않는 경우의 수 1을 뺀 값을 출력한다.

 

예를 들어

주어진 예제 첫번째 케이스에서

headgear 2가지, eyewear 1가지를 입력 받았기 때문에

최종 result 값은

( 2 + 1 ) * ( 1 + 1 ) = 6

에서 아무것도 입지 않는 경우 1을 뺀 5가 출력값이 된다.

'Algorithm' 카테고리의 다른 글

[백준] 1931 회의실 배정 / python  (1) 2024.04.26
[백준] 2xn 타일링 / python  (0) 2024.04.24
[백준] 11047 동전 0 / python  (0) 2024.04.23
[백준] 11723 집합 / python  (0) 2024.04.22
[백준] 2630 색종이 만들기 / python  (2) 2024.04.22
 

11047번: 동전 0

첫째 줄에 N과 K가 주어진다. (1 ≤ N ≤ 10, 1 ≤ K ≤ 100,000,000) 둘째 줄부터 N개의 줄에 동전의 가치 Ai가 오름차순으로 주어진다. (1 ≤ Ai ≤ 1,000,000, A1 = 1, i ≥ 2인 경우에 Ai는 Ai-1의 배수)

www.acmicpc.net

준규가 가지고 있는 동전은 총 N종류이고, 각각의 동전을 매우 많이 가지고 있다.

동전을 적절히 사용해서 그 가치의 합을 K로 만들려고 한다. 이때 필요한 동전 개수의 최솟값을 구하는 프로그램을 작성하시오.

 

 

입력

첫째 줄에 N과 K가 주어진다. (1 ≤ N ≤ 10, 1 ≤ K ≤ 100,000,000)

둘째 줄부터 N개의 줄에 동전의 가치 Ai가 오름차순으로 주어진다. (1 ≤ Ai ≤ 1,000,000, A1 = 1, i ≥ 2인 경우에 Ai는 Ai-1의 배수)

 

 

출력

첫째 줄에 K원을 만드는데 필요한 동전 개수의 최솟값을 출력한다.

 

 

코드

import sys
input = sys.stdin.readline

n, k = map(int, input().split())
value = []
for _ in range(n):
    value.append(int(input()))
value.sort(reverse=True)

cnt = 0
for i in value:
    if k == 0:
        break
    cnt += k//i
    k %= i

print(cnt)

 

가장 큰 단위부터 나누기 위해 동전의 값을 저장해둔 리스트를 내림차순으로 다시 정렬하였다.

 

몫은 cnt변수에 더하고, 나눠진 나머지를 다시 k에 저장한다.

k가 0이 될 때까지 반복한다.

 

예를 들어 4200원일 때

1000원으로 나누면 몫은 4가 되고 나머지는 200이 된다.

따라서 4는 cnt 변수에 추가하면 되고

나머지 200은 다음으로 나눠지는 단위 100으로 나눈다.

'Algorithm' 카테고리의 다른 글

[백준] 2xn 타일링 / python  (0) 2024.04.24
[백준] 9375 패션왕 신해빈 / python  (0) 2024.04.23
[백준] 11723 집합 / python  (0) 2024.04.22
[백준] 2630 색종이 만들기 / python  (2) 2024.04.22
[백준] 1764 듣보잡 / python  (1) 2024.04.20

+ Recent posts