문제


비어있는 공집합 S가 주어졌을 때, 아래 연산을 수행하는 프로그램을 작성하시오.

  • add x: S에 x를 추가한다. (1 ≤ x ≤ 20) S에 x가 이미 있는 경우에는 연산을 무시한다.
  • remove x: S에서 x를 제거한다. (1 ≤ x ≤ 20) S에 x가 없는 경우에는 연산을 무시한다.
  • check x: S에 x가 있으면 1을, 없으면 0을 출력한다. (1 ≤ x ≤ 20)
  • toggle x: S에 x가 있으면 x를 제거하고, 없으면 x를 추가한다. (1 ≤ x ≤ 20)
  • all: S를 {1, 2, ..., 20} 으로 바꾼다.
  • empty: S를 공집합으로 바꾼다.

 

입력


첫째 줄에 수행해야 하는 연산의 수 M (1 ≤ M ≤ 3,000,000)이 주어진다.

둘째 줄부터 M개의 줄에 수행해야 하는 연산이 한 줄에 하나씩 주어진다.

 

출력


check 연산이 주어질때마다, 결과를 출력한다.

 

예제 입력과 출력

 

 

정답

 

import sys
input = lambda : sys.stdin.readline().strip()

m=int(input())
s=[]
for i in range(m):
    a=input().split()

    if a[0] == 'all':
        s.clear()
        s=[i for i in range(1,21)]
        continue
    elif a[0] == 'empty':
        s.clear()
        continue

    num=int(a[1])
    if a[0] == 'add':
        if num not in s:
            s.append(num)
    elif a[0] == 'remove':
        if num in s:
            s.remove(num)
    elif a[0] == 'check':
        if num in s:
            print(1)
        else:
            print(0)
    elif a[0] == 'toggle':
        if num in s:
            s.remove(num)
        else:
            s.append(num)

 


백준 알고리즘 11723번 : https://www.acmicpc.net/problem/11723

 

11723번: 집합

첫째 줄에 수행해야 하는 연산의 수 M (1 ≤ M ≤ 3,000,000)이 주어진다. 둘째 줄부터 M개의 줄에 수행해야 하는 연산이 한 줄에 하나씩 주어진다.

www.acmicpc.net

 

에라토스테네스의 체

에라토스테네스의 체는 소수를 판별하는 알고리즘으로 많은 소수를 구하거나 특정 범위의 소수를 구할 때 유용합니다.

 

n=100
a=[]

for i in range(2,n+1):
    for j in range(2,i):
        if i%j == 0:
            break
    else:
        a.append(i)

# 출력>>[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
print(a)

기본적인 소수를 구하는 방법으로 특정 수보다 작은 모든 수로 나눠서 소수인지를 판단합니다.
위 방법은 정확하지만 범위의 소수를 모두 구할 때는 효율적이지 않습니다.

 

따라서 에라토스테네스의 체를 이용하면 시간을 줄이고 쉽게 소수를 구할 수 있습니다.

 

에라토스테네스의 체 알고리즘은

1. 2부터 소수를 구하고자 하는 구간의 모든 수를 나열합니다.

2. 2부터 시작해서 나열된 수에서 지워지지 않은 수 중 가장 작은 2를 소수로 선택하고 2의 배수를 지웁니다.
3. 3도 지워지지 않았기 때문에 소수로 선택하고 3의 배수를 지웁니다.
4. 4는 지워졌기 때문에 넘어가고 5를 소수로 선택하고 5의 배수를 지웁니다.
5. 2, 3, 4와 같은 과정을 반복합니다.
6. 반복이 끝나면 지워지지 않은 수들을 소수로 출력합니다.

 

n=100
a=[True] * (n+1)
m = int(n ** 0.5)

for i in range(2,m+1):
    if a[i] == True:
        for j in range(i+i,n+1,i):
            a[j]=False

# 출력>>[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
print([i for i in range(2, n+1) if a[i] == True])

에라토스테네스의 체를 이용한 방법입니다.
에라토스테네스의 체를 구할 때는 또한 n의 약수가 sqrt(n) 이하여서 sqrt(n)까지 검사하면 시간을 더 줄일 수 있습니다.
(sqrt는 루트)

문제


1부터 N까지의 수로 이루어진 순열이 있다. 이때, 사전순으로 바로 이전에 오는 순열을 구하는 프로그램을 작성하시오.

사전 순으로 가장 앞서는 순열은 오름차순으로 이루어진 순열이고, 가장 마지막에 오는 순열은 내림차순으로 이루어진 순열이다.

N = 3인 경우에 사전순으로 순열을 나열하면 다음과 같다.

  • 1, 2, 3
  • 1, 3, 2
  • 2, 1, 3
  • 2, 3, 1
  • 3, 1, 2
  • 3, 2, 1

 

입력


첫째 줄에 N(1 ≤ N ≤ 10,000)이 주어진다. 둘째 줄에 순열이 주어진다.

 

출력


첫째 줄에 입력으로 주어진 순열의 이전에 오는 순열을 출력한다. 만약, 사전순으로 가장 처음에 오는 순열인 경우에는 -1을 출력한다.

 

예제 입력과 출력

 

 

알고리즘 분류


순열

 

정답

 

n = int(input())
a = list(map(int, input().split()))

def _10973(a):
    n=len(a)-1
    i = n
    
    while i>0 and a[i-1]<=a[i]: 
        i-=1

    if i==0:
        return False
    
    j = n
    while a[i-1]<=a[j]:
        j-=1
    
    a[i-1],a[j]=a[j],a[i-1]
    
    j=n
    while i<j:
        a[i],a[j]=a[j],a[i]
        i+=1
        j-=1
    return True

if _10973(a) is True:
    for i in a:
        print(i, end=' ')
else:
    print(-1)

 


백준 알고리즘 10973번 : www.acmicpc.net/problem/10973

 

10973번: 이전 순열

첫째 줄에 입력으로 주어진 순열의 이전에 오는 순열을 출력한다. 만약, 사전순으로 가장 처음에 오는 순열인 경우에는 -1을 출력한다.

www.acmicpc.net

 

문제


1부터 N까지의 수로 이루어진 순열이 있다. 이때, 사전순으로 다음에 오는 순열을 구하는 프로그램을 작성하시오.

사전 순으로 가장 앞서는 순열은 오름차순으로 이루어진 순열이고, 가장 마지막에 오는 순열은 내림차순으로 이루어진 순열이다.

N = 3인 경우에 사전순으로 순열을 나열하면 다음과 같다.

  • 1, 2, 3
  • 1, 3, 2
  • 2, 1, 3
  • 2, 3, 1
  • 3, 1, 2
  • 3, 2, 1

 

입력


첫째 줄에 N(1 ≤ N ≤ 10,000)이 주어진다. 둘째 줄에 순열이 주어진다.

 

출력


첫째 줄에 입력으로 주어진 순열의 다음에 오는 순열을 출력한다. 만약, 사전순으로 마지막에 오는 순열인 경우에는 -1을 출력한다.

 

예제 입력과 출력

 

 

알고리즘 분류


순열

 

정답

 

n = int(input())
a = list(map(int, input().split()))

def _10972(a):
    n=len(a)-1
    i = n
    
    while i>0 and a[i-1]>=a[i]:
        i-=1

    if i==0:
        return False
        
    j = n
    while a[i-1]>=a[j]:
        j-=1
    
    a[i-1],a[j]=a[j],a[i-1]
    
    j=n
    while i<j:
        a[i],a[j]=a[j],a[i]
        i+=1
        j-=1
    return True

if _10972(a) is True:
    for i in a:
        print(i, end=' ')
else:
    print(-1)

 


백준 알고리즘 10972번 : https://www.acmicpc.net/problem/10972

 

10972번: 다음 순열

첫째 줄에 입력으로 주어진 순열의 다음에 오는 순열을 출력한다. 만약, 사전순으로 마지막에 오는 순열인 경우에는 -1을 출력한다.

www.acmicpc.net

 

문제


상근이는 1층 빌딩에 침입해 매우 중요한 문서를 훔쳐오려고 한다. 상근이가 가지고 있는 평면도에는 문서의 위치가 모두 나타나 있다. 빌딩의 문은 모두 잠겨있기 때문에, 문을 열려면 열쇠가 필요하다. 상근이는 일부 열쇠를 이미 가지고 있고, 일부 열쇠는 빌딩의 바닥에 놓여져 있다.

상근이가 훔칠 수 있는 문서의 최대 개수를 구하는 프로그램을 작성하시오.

 

입력


첫째 줄에 테스트 케이스의 개수가 주어진다. 테스트 케이스의 수는 100개를 넘지 않는다.

각 테스트 케이스의 첫째 줄에는 지도의 높이와 너비 h와 w (2 ≤ h, w ≤ 100)가 주어진다. 다음 h개 줄에는 빌딩을 나타내는 w개의 문자가 주어지며, 각 문자는 다음 중 하나이다.

  • '.'는 빈 공간을 나타낸다.
  • '*'는 벽을 나타내며, 상근이는 벽을 통과할 수 없다.
  • '$'는 상근이가 훔쳐야하는 문서이다.
  • 알파벳 대문자는 문을 나타낸다.
  • 알파벳 소문자는 열쇠를 나타내며, 그 문자의 대문자인 모든 문을 열 수 있다.

마지막 줄에는 상근이가 이미 가지고 있는 열쇠가 공백없이 주어진다. 만약, 열쇠를 하나도 가지고 있지 않는 경우에는 "0"이 주어진다.

상근이는 처음에는 빌딩의 밖에 있으며, 빌딩 가장자리의 빈 공간이나 문을 통해 빌딩 안팎을 드나들 수 있다. 각각의 문에 대해서, 그 문을 열 수 있는 열쇠의 개수는 0개, 1개, 또는 그 이상이고, 각각의 열쇠에 대해서, 그 열쇠로 열 수 있는 문의 개수도 0개, 1개, 또는 그 이상이다. 열쇠는 여러 번 사용할 수 있다.

 

출력


각 테스트 케이스 마다, 상근이가 훔칠 수 있는 문서의 최대 개수를 출력한다.

 

예제 입력과 출력

 

 

알고리즘 분류


BFS

 

정답

 

from collections import deque
import sys
input= lambda : sys.stdin.readline().strip()

t=int(input())

dx=[-1,0,1,0]
dy=[0,1,0,-1]

def bfs():
    de=deque()
    de.append([0,0])
    ch[0][0]=0
    dq=[deque() for i in range(26)]
    r=0

    while de:
        x,y=de.popleft()

        for i in range(4):
            nx = x + dx[i]
            ny = y + dy[i]

            if 0 <= nx < h+2 and 0 <= ny < w+2:
                
                if a[nx][ny] == '*':
                    continue
            
                if ch[nx][ny] == -1:
                    ch[nx][ny] = 0

                    if a[nx][ny] == '$':
                        r += 1
                    elif 'A' <= a[nx][ny] <= 'Z': # 문인 경우
                        d=ord(a[nx][ny])-ord('A')
                        if alp[d] is False:
                            dq[d].append([nx,ny])
                            continue
                    elif 'a' <= a[nx][ny] <= 'z': # 열쇠인 경우
                        k=ord(a[nx][ny])-ord('a')
                        alp[k]=True
                        while dq[k]:
                            kx,ky=dq[k].popleft()
                            de.append([kx,ky])
                    
                    de.append([nx,ny])
    return r
                
            
while t:
    t -= 1
    h,w=map(int,input().split()) 

    a=[list('.'*(w+2))]
    for i in range(h):
        a.append(list('.'+input()+'.'))
    a.append(list('.'*(w+2)))
    k=input()
    
    ch=[[-1]*(w+2) for i in range(h+2)]
    alp=[False]*26
    
    if k != '0':
        for i in k:
            alp[ord(i)-ord('a')]=True

    print(bfs())

 

이 문제에서 중요한 것은 평면도에서 가로, 세로의 가장자리를 확대해서 답을 구한다는 것입니다,
가로, 세로를 확대해야 하는 이유는 빌딩 밖을 나갔다가 다시 들어와서 문을 여는 경우를 생각해야 하기 때문입니다.

 

배열 alp는 열쇠를 가지고 있는지 여부를 나타내기 위한 것입니다. 처음 가지고 있는 열쇠는 True로 바꿉니다.

bfs를 통해 훔칠 수 있는 문서의 최대 개수를 구합니다.

de를 통해 이동 위치를 나타내고 dq는 문의 위치를 나타냅니다.

 

평면도를 이동하면서 위치가 '*'인 경우는 넘어가고 그 외의 경우는 방문처리를 합니다.

위치

문서($) : 훔칠 수 있는 문서의 개수를 1 더합니다.
문(A~Z) : 열쇠가 있어서 문을 열수있는지 없는지 확인합니다. 열 수 있다면 넘어가고 열수없으면 dq에 넣어줍니다.
             이는 나중에 열쇠가 생기면 dq에 있는 문을 열어줄 때 사용하기 위함입니다.

열쇠(a~z) : alp를 통해 열쇠를 True로 바꿉니다. 또한 해당 열쇠에 대한 dq를 검사해 dq에 있는 값들을 모두 방문할 수 있도록 de에 넣습니다.

 


백준 알고리즘 9328번 : https://www.acmicpc.net/problem/9328

 

9328번: 열쇠

문제 상근이는 1층 빌딩에 침입해 매우 중요한 문서를 훔쳐오려고 한다. 상근이가 가지고 있는 평면도에는 문서의 위치가 모두 나타나 있다. 빌딩의 문은 모두 잠겨있기 때문에, 문을 열려면 열

www.acmicpc.net

 

문제


상근이는 감옥에서 죄수 두 명을 탈옥시켜야 한다. 이 감옥은 1층짜리 건물이고, 상근이는 방금 평면도를 얻었다.

평면도에는 모든 벽과 문이 나타나있고, 탈옥시켜야 하는 죄수의 위치도 나타나 있다. 감옥은 무인 감옥으로 죄수 두 명이 감옥에 있는 유일한 사람이다.

문은 중앙 제어실에서만 열 수 있다. 상근이는 특별한 기술을 이용해 제어실을 통하지 않고 문을 열려고 한다. 하지만, 문을 열려면 시간이 매우 많이 걸린다. 두 죄수를 탈옥시키기 위해서 열어야 하는 문의 개수를 구하는 프로그램을 작성하시오.

 

입력

 

첫째 줄에 테스트 케이스의 개수가 주어진다. 테스트 케이스의 수는 100개를 넘지 않는다.

첫째 줄에는 평면도의 높이 h와 너비 w가 주어진다. (2 ≤ h, w ≤ 100) 다음 h개 줄에는 감옥의 평면도 정보가 주어지며, 빈 공간은 '.', 지나갈 수 없는 벽은 '*', 문은 '#', 죄수의 위치는 '$'이다.

상근이는 감옥 밖을 자유롭게 이동할 수 있고, 평면도에 표시된 죄수의 수는 항상 두 명이다. 각 죄수와 감옥의 바깥을 연결하는 경로가 항상 존재하는 경우만 입력으로 주어진다.

 

출력

 

각 테스트 케이스마다 두 죄수를 탈옥시키기 위해서 열어야 하는 문의 최솟값을 출력한다.

예제 입력과 출력

 

 

알고리즘 분류


BFS

 

정답

 

from collections import deque
import sys
input= lambda : sys.stdin.readline().strip()

t=int(input())

dx=[-1,0,1,0]
dy=[0,1,0,-1]

def bfs(s1,s2):
    ch=[[-1]*(w+2) for i in range(h+2)]
    de=deque()
    de.append([s1,s2])
    ch[s1][s2]=0

    while de:
        x,y=de.popleft()

        for i in range(4):
            nx = x + dx[i]
            ny = y + dy[i]

            if 0 <= nx < h+2 and 0 <= ny < w+2:
                if ch[nx][ny] == -1:
                    if a[nx][ny] == '.' or a[nx][ny] == '$':
                        ch[nx][ny] = ch[x][y]
                        de.appendleft([nx,ny])
                        
                    if a[nx][ny] == '#':
                        ch[nx][ny] = ch[x][y] +1
                        de.append([nx,ny])
    return ch

while t:
    t -= 1
    h,w=map(int,input().split()) 

    a=[list('.'*(w+2))]
    for i in range(h):
        a.append(list('.'+input().strip()+'.'))
    a.append(list('.'*(w+2)))
    
    s=[]
    for i in range(h+2):
        for j in range(w+2):
            if a[i][j] == '$': # 죄수
                s.append([i,j])
    
    one=bfs(s[0][0],s[0][1])
    two=bfs(s[1][0],s[1][1])
    three=bfs(0,0)
    m=sys.maxsize
    
    for i in range(h+2):
        for j in range(w+2):
            r=one[i][j]+two[i][j]+three[i][j]

            if a[i][j] == '*':
                continue
            if a[i][j] == '#':
                r -= 2
            m=min(m,r)

    print(m)


이 문제에서 중요한 것은 문제에서 주어진 평면도에서 가로, 세로의 가장자리를 확대해서 답을 구한다는 것입니다.
가로, 세로를 확대해도 괜찮은 이유는 확대한 곳에는 문이 없기 때문에 따로 열어야 하는 문의 개수가 올라가지 않기 때문입니다.

 

one : 첫 번째 죄수가 출발해서 문을 여는 경우
two : 두 번째 죄수가 출발해서 문을 여는 경우
three : 밖에서 출발해서 문을 여는 경우

 

3가지 경우에 bfs를 통해 ch에 열어야 하는 문의 개수를 저장하고 리턴합니다.
bfs 과정에서 통과하려는 곳이 '.'인 경우 먼저 방문할 수 있게 appendleft를 이용합니다.

 

평면도의 각 위치에 대한 열어야 하는 문의 개수를 비교합니다.
위치가 '#'인 경우는 3명이 모두 문을 열었기 때문에 한명만 열면 모두 통과할 수 있기 때문에 -2를 합니다.
그 후 최소값을 구하여 출력합니다.

 


백준 알고리즘 9376번 : https://www.acmicpc.net/problem/9376

 

9376번: 탈옥

문제 상근이는 감옥에서 죄수 두 명을 탈옥시켜야 한다. 이 감옥은 1층짜리 건물이고, 상근이는 방금 평면도를 얻었다. 평면도에는 모든 벽과 문이 나타나있고, 탈옥시켜야 하는 죄수의 위치도 �

www.acmicpc.net

 

+ Recent posts