728x90
반응형

https://www.acmicpc.net/problem/18352

 

18352번: 특정 거리의 도시 찾기

첫째 줄에 도시의 개수 N, 도로의 개수 M, 거리 정보 K, 출발 도시의 번호 X가 주어진다. (2 ≤ N ≤ 300,000, 1 ≤ M ≤ 1,000,000, 1 ≤ K ≤ 300,000, 1 ≤ X ≤ N) 둘째 줄부터 M개의 줄에 걸쳐서 두 개

www.acmicpc.net

1.

처음에 풀었을 때 BFS로 미로찾기와 비슷하게 풀었는데 메모리 초과가 생겼다. 

from collections import deque
import sys
input = sys.stdin.readline
n,m,k,x = map(int,input().split())
#도시의 개수 n, 도로의 개수 m, 거리 정보 k, 출발 도시의 번호 x
graph=[[0]*(n+1) for _ in range(n+1)]
distance=[99999]*(n+1)
visited=[False]*(n+1)
for i in range(m):
    a,b=map(int,input().split())
    graph[a][b]=1

def bfs(v):
    q=deque([v])
    distance[v]=0
    while q:
        x = q.popleft()
        for i in range(1,n+1):
            if graph[x][i]==1:
                q.append(i)
                distance[i]=min(distance[x]+1,distance[i])
bfs(x)
answer=[]
for i in range(len(distance)):
    if distance[i]==k:
        answer.append(i)
if len(answer)==0:
    print(-1)
else:
    for i in range(len(answer)):
        print(answer[i])

거리가 K인 것만 출력하면 된다는 사실과 graph를 통해 모든 지점을 탐색할 필요는 없다는 점을 통해 메모리 초과를 해결할 수 있었다.

 

2.

모든 도로의 거리는 1이다. 너비 우선 탐색을 이용하여 해결할 수 있다. 앞서 미로찾기와 같이 이동할 때의 거리는 +1하면서 해결할 수 있다. 문제의 조건에서 노드의 개수 N은 최대 300000개, 도로의 개수 M은 최대 1000000개이다. 따라서 BFS를 사용하여 시간 복잡도 O(N+M)으로 작동하는 소스코드를 작성하여 해결할 수 있다.

from collections import deque
n,m,k,x = map(int,input().split())
graph = [[] for _ in range(n+1)]
for _ in range(m):
    a,b = map(int,input().split())
    graph[a].append(b)
distance = [-1]*(n+1)
distance[x]=0

q=deque([x])
while q:
    now = q.popleft()
    for next_node in graph[now]:
        if distance[next_node]==-1:
            distance[next_node]=distance[now]+1
            q.append(next_node)
check = False
for i in range(1,n+1):
    if distance[i]==k:
        print(i)
        check = True
if check==False:
    print(-1)

3.

다익스트라 알고리즘이 유용하게 쓰이진 않지만 그 틀을 사용해서 풀었다.

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

n,m,k,x = map(int,input().split())
visited = [False]*(n+1)
graph = [[] for _ in range(n+1)]
answer=[]

for _ in range(m):
    i,j = map(int,input().split())
    graph[i].append(j)

queue=deque()
queue.append((x,0))
visited[x]=True

while queue:
    v,dist=queue.popleft()
    if dist == k:
        answer.append(v)
    elif dist<k:
        for i in graph[v]:
            if not visited[i]:
                visited[i]=True
                queue.append((i,dist+1))

if len(answer)==0:
    print(-1)
else:
    answer.sort()
    for i in range(len(answer)):
        print(answer[i])
728x90
반응형
728x90
반응형

https://www.acmicpc.net/problem/2178

 

2178번: 미로 탐색

첫째 줄에 두 정수 N, M(2 ≤ N, M ≤ 100)이 주어진다. 다음 N개의 줄에는 M개의 정수로 미로가 주어진다. 각각의 수들은 붙어서 입력으로 주어진다.

www.acmicpc.net

[문제 풀이]

(1,1)에서 출발하여 (N,M)까지 가는 길 중 최소의 칸 수를 가야하는 길을 구해야 한다. 이 문제는 1인 영역만 일단 지나도록 설계한다. 1인 지역을 지나갈때 그 전의 지역의 graph 수에서 1을 추가해준다. 그렇게 하면 graph의 (N,M) 좌표를 출력하면 몇게의 길을 지나왔는지 알 수 있다. 나는 BFS를 통해 풀었다.

 

from collections import deque
n,m = map(int,input().split())
graph=[]
for i in range(n):
    graph.append(list(map(int,input())))
def bfs(a,b):
    q=deque()
    q.append((a,b))
    dx=[-1,1,0,0]
    dy=[0,0,1,-1]
    while q:
        x,y = q.popleft()
        for i in range(4):
            nx=x+dx[i]
            ny=y+dy[i]
            if nx>=0 and nx<n and ny>=0 and ny<m and graph[nx][ny]==1:
                q.append((nx,ny))
                graph[nx][ny]=graph[x][y]+1
bfs(0,0)
print(graph[n-1][m-1])
728x90
반응형
728x90
반응형

https://www.acmicpc.net/problem/10845

 

10845번: 큐

첫째 줄에 주어지는 명령의 수 N (1 ≤ N ≤ 10,000)이 주어진다. 둘째 줄부터 N개의 줄에는 명령이 하나씩 주어진다. 주어지는 정수는 1보다 크거나 같고, 100,000보다 작거나 같다. 문제에 나와있지

www.acmicpc.net

from collections import deque
import sys
input = sys.stdin.readline
q=deque()
n= int(input())
for i in range(n):
    question = input().split()
    if len(question)==2:
        order = question[0]
        number = int(question[1])
        q.append(number)
    else:
        if question[0]=='pop':
            if len(q)==0:
                print(-1)
            else:
                print(q.popleft())
        elif question[0]=='size':
            print(len(q))
        elif question[0]=='empty':
            if len(q)==0:
                print(1)
            else:print(0)
        elif question[0]=='front':
            if len(q)==0:
                print(-1)
            else:
                print(q[0])
        elif question[0]=='back':
            if len(q)==0:
                print(-1)
            else:
                print(q[-1])

기본적으로 큐를 구현하여 푸는 문제이다. 큐의 다양한 기능들을 조건문을 통하여 해결하였다.

 

https://www.acmicpc.net/problem/10866

 

10866번: 덱

첫째 줄에 주어지는 명령의 수 N (1 ≤ N ≤ 10,000)이 주어진다. 둘째 줄부터 N개의 줄에는 명령이 하나씩 주어진다. 주어지는 정수는 1보다 크거나 같고, 100,000보다 작거나 같다. 문제에 나와있지

www.acmicpc.net

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

q=deque()
n=int(input())
for i in range(n):
    question = input().split()
    if len(question)==2:
        order=question[0]
        number=question[1]
        if order=='push_front':
            q.appendleft(number)
        elif order=='push_back':
            q.append(number)
    else:
        if question[0]=='pop_front':
            if q:
                print(q.popleft())
            else:
                print(-1)
        elif question[0]=='pop_back':
            if q:
                print(q.pop())
            else:
                print(-1)
        elif question[0]=='size':
            print(len(q))
        elif question[0]=='empty':
            if q:
                print(0)
            else:
                print(1)
        elif question[0]=='front':
            if q:
                print(q[0])
            else:
                print(-1)
        elif question[0]=='back':
            if q:
                print(q[-1])
            else:
                print(-1)

10845와 같이 deque를 사용하여서 문제를 해결하였다.

 

위에 두 문제에서 핵심은 input()대신 sys.stdin.readline()을 사용하여야 된다는 것이다.

반복문으로 여러줄을 입력 받아야 할 때 input()은 시간초과를 일으킬 수 있다.

 

# ) sys.stdin.readline()은 한줄 단위로 입력받기 때문에, enter가 같이 입력이된다.

# ) strip()은 문자열 맨 앞과 맨 끝의 공백문자를 제거한다.

 

 

https://www.acmicpc.net/problem/1406

 

1406번: 에디터

첫째 줄에는 초기에 편집기에 입력되어 있는 문자열이 주어진다. 이 문자열은 길이가 N이고, 영어 소문자로만 이루어져 있으며, 길이는 100,000을 넘지 않는다. 둘째 줄에는 입력할 명령어의 개수

www.acmicpc.net

[문제 풀이]

이 문제는 위에 두 문제와 비슷하다고 생각하고 쉽게 풀려고 했는데 잘 풀리지 않았다. 먼저 위에 두 문제처럼 풀었다.

from collections import deque
import sys
input = sys.stdin.readline
q=deque()
str = input()
for i in range(len(str)):
    q.append(str[i])
m=int(input())
cursor=len(q)
for i in range(m):
    question=input().split()
    if len(question)==2:
        number=question[1]
        q.insert(cursor,number)
        cursor+=1
    else:
        if question[0]=='L':
            if cursor!=0:
                cursor-=1
        elif question[0]=='D':
            if cursor!=len(q):
                cursor+=1
        elif question[0]=='B':
            if cursor!=0:
                q = list(q)
                q.pop(cursor-1)
                q=deque(q)
                cursor-=1
for i in range(len(q)):
    print(q[i],end='')

위에 방식대로 풀려고 했는데 시간초과, 런타임에러(TypeError)같은 에러가 계속 났다. 시간 초과를 해결하는 것이 이 문제의 핵심이라 생각했다. 문제를 보면 시간제한이 다른 문제보다 적다.

input도 sys.stdin.readline으로 바꿔도 보고, 내가 할 수 있는 일들을 해봤지만 시간초과는 계속 났다. 그리고 입력 부분을 다시 봤다.

내가 푼 방식으로는 문자열의 길이가 N일때 O(N)의 시간복잡도가 발생한다. 그렇다면 최악의 경우 100,000길이인 문자열을 500,000번 다루면 100,000 X 500,000 번의 연산이 필요하게 된다. M을 줄이기보다 문자열 통째로 연산하는 것을 부분적으로 할 수 있도록 줄여봐야 된다고 생각했다.

https://bnzn2426.tistory.com/112

 

[백준] 알고리즘 1406번 - python 풀이

https://www.acmicpc.net/problem/1406 1406번: 에디터 문제 한 줄로 된 간단한 에디터를 구현하려고 한다. 이 편집기는 영어 소문자만을 기록할 수 있는 편집기로, 최대 600,000글자까지 입력할 수 있다. 이 편

bnzn2426.tistory.com

여기서 많은 도움을 받게 되었다. 

두 개의 스택을 이용해 커서의 앞 부분과 커서의 뒷 부분을 구분하여 생각한다.

먼저 첫번째 스택에 모두 들어가고 두번째 스택은 비어있다. 만약 L을 입력받아 커서가 왼쪽으로 움직인다면 첫번째 스택은 pop을 통해 꺼내고 두번째 스택에 push되는 것이다. 

반대로 D를 입력받으면 첫번째 스택에 push, 두번째 스택에서 pop을 하는 것이다. 

 

from sys import stdin
input = stdin.readline
first = list(stdin.readline().strip())
second = []
m= int(input())
for i in range(m):
    question=input().split()
    if question[0]=='L':
        if first: #첫번째 스택이 존재할때 (없으면 더 왼쪽으로 커서가 못가니까)
            second.append(first.pop())
    elif question[0]=='D':
        if second:
            first.append(second.pop())
    elif question[0]=='B':
        if first:
            first.pop()
    elif question[0]=='P':
        first.append(question[1])
print("".join(first+list(reversed(second))))

 

 

728x90
반응형
728x90
반응형

https://www.acmicpc.net/problem/7569

 

7569번: 토마토

첫 줄에는 상자의 크기를 나타내는 두 정수 M,N과 쌓아올려지는 상자의 수를 나타내는 H가 주어진다. M은 상자의 가로 칸의 수, N은 상자의 세로 칸의 수를 나타낸다. 단, 2 ≤ M ≤ 100, 2 ≤ N ≤ 100,

www.acmicpc.net

문제

철수의 토마토 농장에서는 토마토를 보관하는 큰 창고를 가지고 있다. 토마토는 아래의 그림과 같이 격자모양 상자의 칸에 하나씩 넣은 다음, 상자들을 수직으로 쌓아 올려서 창고에 보관한다.

창고에 보관되는 토마토들 중에는 잘 익은 것도 있지만, 아직 익지 않은 토마토들도 있을 수 있다. 보관 후 하루가 지나면, 익은 토마토들의 인접한 곳에 있는 익지 않은 토마토들은 익은 토마토의 영향을 받아 익게 된다. 하나의 토마토에 인접한 곳은 위, 아래, 왼쪽, 오른쪽, 앞, 뒤 여섯 방향에 있는 토마토를 의미한다. 대각선 방향에 있는 토마토들에게는 영향을 주지 못하며, 토마토가 혼자 저절로 익는 경우는 없다고 가정한다. 철수는 창고에 보관된 토마토들이 며칠이 지나면 다 익게 되는지 그 최소 일수를 알고 싶어 한다.

토마토를 창고에 보관하는 격자모양의 상자들의 크기와 익은 토마토들과 익지 않은 토마토들의 정보가 주어졌을 때, 며칠이 지나면 토마토들이 모두 익는지, 그 최소 일수를 구하는 프로그램을 작성하라. 단, 상자의 일부 칸에는 토마토가 들어있지 않을 수도 있다.

입력

첫 줄에는 상자의 크기를 나타내는 두 정수 M,N과 쌓아올려지는 상자의 수를 나타내는 H가 주어진다. M은 상자의 가로 칸의 수, N은 상자의 세로 칸의 수를 나타낸다. 단, 2 ≤ M ≤ 100, 2 ≤ N ≤ 100, 1 ≤ H ≤ 100 이다. 둘째 줄부터는 가장 밑의 상자부터 가장 위의 상자까지에 저장된 토마토들의 정보가 주어진다. 즉, 둘째 줄부터 N개의 줄에는 하나의 상자에 담긴 토마토의 정보가 주어진다. 각 줄에는 상자 가로줄에 들어있는 토마토들의 상태가 M개의 정수로 주어진다. 정수 1은 익은 토마토, 정수 0 은 익지 않은 토마토, 정수 -1은 토마토가 들어있지 않은 칸을 나타낸다. 이러한 N개의 줄이 H번 반복하여 주어진다.

토마토가 하나 이상 있는 경우만 입력으로 주어진다.

출력

여러분은 토마토가 모두 익을 때까지 최소 며칠이 걸리는지를 계산해서 출력해야 한다. 만약, 저장될 때부터 모든 토마토가 익어있는 상태이면 0을 출력해야 하고, 토마토가 모두 익지는 못하는 상황이면 -1을 출력해야 한다.

 

예제 입력 1 

5 3 1
0 -1 0 0 0
-1 -1 0 1 1
0 0 0 1 1

예제 출력 1 

-1

 

예제 입력 2 

5 3 2
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 1 0 0
0 0 0 0 0

예제 출력 2 

4

 

예제 입력 3 

4 3 2
1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1
-1 -1 -1 -1
1 1 1 -1

예제 출력 3 

0

 

[문제 풀이]

먼저 이전에 풀었던 토마토 2차원 문제에서 이 문제는 3차원 문제로 업그레이드 되었다. 3차원 배열을 입력받는 부분은 예제의 입력에서 힌트를 얻었다. h만큼 덩어리가 생기므로 m은 list로 해서 입력받고 그 입력 받은 리스트를 range(n)으로 for문 한 번, range(h)로 for문 한 번 사용해서 입력받는다. (입력받은걸 확인하기 위해 매번 print()사용한다..)

 

데큐를 사용해서 bfs를 이용하겠다. 일단 익은 것들이 하루에 다른 덜익은 토마토를 익히는 건 범위의 한계가 있다. 하루에 상하좌우해서 1칸씩 밖에 안된다. 우리가 원래 사용하던 bfs를 변형시키면 된다. 

먼저 처음에 주어진 토마토 박스에서 익은 것들을 q에 저장해준다.(q는 deque()로 만든 것이다) 그리고 q에 들어간 값들의 개수를 count에 저장한다. (count=len(q)) 그리고 dx,dy,dz를 count만큼만 해주면 그날 하루하루 익은 것들만 0에서 1로 바꿀 수 있다.

나머지 조건들도 (처음부터 다익은 경우, 시간이 아무리 지나도 안익는 것 존재하는 경우)들도 처리해준다.

 

from collections import deque
m,n,h = map(int,input().split())
#tomato[h][n][m]
tomato=[[list(map(int,input().split())) for _ in range(n)] for _ in range(h)]
#print(tomato)
q=deque()
for i in range(h):
    for j in range(n):
        for k in range(m):
            if tomato[i][j][k]==1:
                q.append((i,j,k))
day=0
while q:
    count=len(q)
    dx=[-1,1,0,0,0,0]
    dy=[0,0,-1,1,0,0]
    dz=[0,0,0,0,-1,1]
    day += 1
    for _ in range(count):
        z, y, x = q.popleft()
        for i in range(6):
            nx = x+dx[i]
            ny = y+dy[i]
            nz = z+dz[i]
            if 0<=nz<h and 0<=ny<n and 0<=nx<m and tomato[nz][ny][nx]==0:
                q.append((nz,ny,nx))
                tomato[nz][ny][nx]=1
            else:
                continue
for i in range(h):
    for j in range(n):
        for k in range(m):
            if tomato[i][j][k]==0:
                print(-1)
                exit(0)
print(day-1)

728x90
반응형
728x90
반응형

https://www.acmicpc.net/problem/1261

 

1261번: 알고스팟

첫째 줄에 미로의 크기를 나타내는 가로 크기 M, 세로 크기 N (1 ≤ N, M ≤ 100)이 주어진다. 다음 N개의 줄에는 미로의 상태를 나타내는 숫자 0과 1이 주어진다. 0은 빈 방을 의미하고, 1은 벽을 의미

www.acmicpc.net

문제

알고스팟 운영진이 모두 미로에 갇혔다. 미로는 N*M 크기이며, 총 1*1크기의 방으로 이루어져 있다. 미로는 빈 방 또는 벽으로 이루어져 있고, 빈 방은 자유롭게 다닐 수 있지만, 벽은 부수지 않으면 이동할 수 없다.

알고스팟 운영진은 여러명이지만, 항상 모두 같은 방에 있어야 한다. 즉, 여러 명이 다른 방에 있을 수는 없다. 어떤 방에서 이동할 수 있는 방은 상하좌우로 인접한 빈 방이다. 즉, 현재 운영진이 (x, y)에 있을 때, 이동할 수 있는 방은 (x+1, y), (x, y+1), (x-1, y), (x, y-1) 이다. 단, 미로의 밖으로 이동 할 수는 없다.

벽은 평소에는 이동할 수 없지만, 알고스팟의 무기 AOJ를 이용해 벽을 부수어 버릴 수 있다. 벽을 부수면, 빈 방과 동일한 방으로 변한다.

만약 이 문제가 알고스팟에 있다면, 운영진들은 궁극의 무기 sudo를 이용해 벽을 한 번에 다 없애버릴 수 있지만, 안타깝게도 이 문제는 Baekjoon Online Judge에 수록되어 있기 때문에, sudo를 사용할 수 없다.

현재 (1, 1)에 있는 알고스팟 운영진이 (N, M)으로 이동하려면 벽을 최소 몇 개 부수어야 하는지 구하는 프로그램을 작성하시오.

입력

첫째 줄에 미로의 크기를 나타내는 가로 크기 M, 세로 크기 N (1 ≤ N, M ≤ 100)이 주어진다. 다음 N개의 줄에는 미로의 상태를 나타내는 숫자 0과 1이 주어진다. 0은 빈 방을 의미하고, 1은 벽을 의미한다.

(1, 1)과 (N, M)은 항상 뚫려있다.

출력

첫째 줄에 알고스팟 운영진이 (N, M)으로 이동하기 위해 벽을 최소 몇 개 부수어야 하는지 출력한다.

 

예제 입력 1 

3 3

011

111

110

예제 출력 1 

3

예제 입력 2 

4 2

0001

1000

예제 출력 2 

0

예제 입력 3 

6 6

001111

010000

001111

110001

011010

100010

예제 출력 3 

2

 

[문제 해설]

이 문제는 벽에 대한 것을 어떻게 해결해야될까가 고민이였다. 벽을 부수는 횟수를 최소한으로 해서 탈출을 해야 한다. 사실 벽을 부순다는 행위를 거리의 길이 즉 가중치라고 생각하면 된다. 그래서 거리가 짧은 곳으로 다녀 목적지까지 도달하게 해주는 다익스트라 알고리즘을 사용하면 된다. 다익스트라 알고리즘보다는 거의 BFS를 사용해서 푼 것 같다.

 

BFS대로 푸는데 최대한 벽이 없는 곳으로 가는 것이 유리하다. 벽이 없는 곳을 만났을 때는 큐에서 appendleft를 이용하여 먼저 가게 하고 벽이 있는 곳을 만나면 그냥 append를 통해 큐에 추가해준다. 

 

from collections import deque
m,n=map(int,input().split())
graph=[list(map(int,input())) for _ in range(n)]
bback=[[-1]*m for _ in range(n)]#가중치
dx=[-1,1,0,0]#상하좌우
dy=[0,0,-1,1]#상하좌우

q=deque()
q.append((0,0))
bback[0][0]=0
while q:
    x,y = q.popleft()
    for i in range(4):
        nx=x+dx[i]
        ny=y+dy[i]
        if nx<0 or nx>=n or ny<0 or ny>=m:
            continue
        if bback[nx][ny]==-1:
            if graph[nx][ny]==0:
                bback[nx][ny]=bback[x][y]
                q.appendleft((nx,ny))
            elif graph[nx][ny]==1:
                bback[nx][ny]=bback[x][y]+1
                q.append((nx,ny))
print(bback[n-1][m-1])

 

 

728x90
반응형
728x90
반응형

www.acmicpc.net/problem/7576

 

7576번: 토마토

첫 줄에는 상자의 크기를 나타내는 두 정수 M,N이 주어진다. M은 상자의 가로 칸의 수, N은 상자의 세로 칸의 수를 나타낸다. 단, 2 ≤ M,N ≤ 1,000 이다. 둘째 줄부터는 하나의 상자에 저장된 토마토

www.acmicpc.net

문제

철수의 토마토 농장에서는 토마토를 보관하는 큰 창고를 가지고 있다. 토마토는 아래의 그림과 같이 격자 모양 상자의 칸에 하나씩 넣어서 창고에 보관한다. 

창고에 보관되는 토마토들 중에는 잘 익은 것도 있지만, 아직 익지 않은 토마토들도 있을 수 있다. 보관 후 하루가 지나면, 익은 토마토들의 인접한 곳에 있는 익지 않은 토마토들은 익은 토마토의 영향을 받아 익게 된다. 하나의 토마토의 인접한 곳은 왼쪽, 오른쪽, 앞, 뒤 네 방향에 있는 토마토를 의미한다. 대각선 방향에 있는 토마토들에게는 영향을 주지 못하며, 토마토가 혼자 저절로 익는 경우는 없다고 가정한다. 철수는 창고에 보관된 토마토들이 며칠이 지나면 다 익게 되는지, 그 최소 일수를 알고 싶어 한다.

토마토를 창고에 보관하는 격자모양의 상자들의 크기와 익은 토마토들과 익지 않은 토마토들의 정보가 주어졌을 때, 며칠이 지나면 토마토들이 모두 익는지, 그 최소 일수를 구하는 프로그램을 작성하라. 단, 상자의 일부 칸에는 토마토가 들어있지 않을 수도 있다.

입력

첫 줄에는 상자의 크기를 나타내는 두 정수 M,N이 주어진다. M은 상자의 가로 칸의 수, N은 상자의 세로 칸의 수를 나타낸다. 단, 2 ≤ M,N ≤ 1,000 이다. 둘째 줄부터는 하나의 상자에 저장된 토마토들의 정보가 주어진다. 즉, 둘째 줄부터 N개의 줄에는 상자에 담긴 토마토의 정보가 주어진다. 하나의 줄에는 상자 가로줄에 들어있는 토마토의 상태가 M개의 정수로 주어진다. 정수 1은 익은 토마토, 정수 0은 익지 않은 토마토, 정수 -1은 토마토가 들어있지 않은 칸을 나타낸다.

토마토가 하나 이상 있는 경우만 입력으로 주어진다.

출력

여러분은 토마토가 모두 익을 때까지의 최소 날짜를 출력해야 한다. 만약, 저장될 때부터 모든 토마토가 익어있는 상태이면 0을 출력해야 하고, 토마토가 모두 익지는 못하는 상황이면 -1을 출력해야 한다.

 

예제 입력1

6 4
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 1

예제 출력1

8

 

예제 입력2

6 4
0 -1 0 0 0 0
-1 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 1

예제 출력2

-1

 

 

[문제 해설]

문제를 해석하면 1은 익은 토마토, 0은 익지 않은 토마토 -1은 토마토가 없는 곳이다. 하루가 지나면 1 옆에 0은 1로 변한다. (옆이라는 것은 대각선이 아닌 가로, 세로로 인접한 곳을 의미) 

 

dx,dy를 통해 상하좌우를 탐색해야 되므로 bfs를 떠올렸다. 일단 bfs로 근처 0이 1로 변하는 것을 짜고 정답인 걸리는 시간은 나중에 생각해야 겠다고 결정했다.

 

입력을 받고, bfs에 사용되는 큐에는 토마토 중 익은것인 1이 되어있는 것을 넣어주었다.

from collections import deque
m,n = map(int,input().split())
tomato=[]
for i in range(n):
    tomato.append(list(map(int,input().split())))

queue=deque()
for i in range(n):
    for j in range(m):
        if tomato[i][j]==1:
            queue.append((i,j))

(bfs에서는 deque를 사용하므로 collections import해주었다.)

 

그리고 bfs를 사용해서 1. 범위를 넘어간 곳이면 continue 2. 0인 곳을 만나면 1로 바꾸어주고 큐에 넣어줌. 3. -1인 곳도 그냥 continue

from collections import deque
m,n = map(int,input().split())
tomato=[]
for i in range(n):
    tomato.append(list(map(int,input().split())))

queue=deque()
for i in range(n):
    for j in range(m):
        if tomato[i][j]==1:
            queue.append((i,j))
            
dx = [-1, 1, 0, 0]  # 상, 하, 좌, 우
dy = [0, 0, -1, 1]
while queue:
    x,y=queue.popleft()
    for i in range(4):
        nx=x+dx[i]
        ny=y+dy[i]
        if nx<0 or nx>=n or ny<0 or ny>=m:
            continue
        if tomato[nx][ny]==0:
            tomato[nx][ny]=1
            queue.append((nx, ny))
        if tomato[nx][ny] == -1:
            continue

 

그리고 이제 여기까지 되었으면 마지막 단계인 토마토가 다익는데 걸리는 기간을 확인해야 된다. 여기서 떠올린 생각은 토마토가 완성되는데 걸리는 시간은 큐에 원소의 갯수에 따라 달라질 수 있다는 것이다. 

만약 처음에 tomato맵에서 1이었던 것이 2개이면 동시에 bfs함수를 돌려서 그날에 익는 갯수를 확인해야 될 것이다. 그러므로 for문을 통해 tomato맵에서 1이었던 것의 갯수만큼만 반복해주면 된다.

(이미 한것에 한해서는 bfs함수를 해서 주위엔 익은 상태이기 때문에 신경을 안써주어도 되기 때문)

 

[최종 정답]

from collections import deque

m, n = map(int, input().split())
tomato = []
for _ in range(n):
    tomato.append(list(map(int, input().split())))
# 1은 익은 토마토, 정수 0은 익지 않은 토마토, 정수 -1은 토마토가 들어있지 않음
dx = [-1, 1, 0, 0]  # 상, 하, 좌, 우
dy = [0, 0, -1, 1]
queue = deque()
for i in range(n):
    for j in range(m):
        if tomato[i][j]==1:
            queue.append((i, j))
day = 1
count = len(queue)
while queue:
    for i in range(count):
        x, y = queue.popleft()
        for i in range(4):
            nx = x + dx[i]
            ny = y + dy[i]
            if nx<0 or nx>=n or ny<0 or ny>=m:
                continue
            if tomato[nx][ny] == 0:
                tomato[nx][ny] = 1
                queue.append((nx, ny))
            if tomato[nx][ny] == -1:
                continue
    day+=1
    count=len(queue)
answer=0
for i in range(n):
    for j in range(m):
        if tomato[i][j]==0:
            answer=-1
if answer!=-1:
    answer=day

print(answer)
728x90
반응형
728x90
반응형

www.acmicpc.net/problem/1697

 

1697번: 숨바꼭질

수빈이는 동생과 숨바꼭질을 하고 있다. 수빈이는 현재 점 N(0 ≤ N ≤ 100,000)에 있고, 동생은 점 K(0 ≤ K ≤ 100,000)에 있다. 수빈이는 걷거나 순간이동을 할 수 있다. 만약, 수빈이의 위치가 X일

www.acmicpc.net

문제

수빈이는 동생과 숨바꼭질을 하고 있다. 수빈이는 현재 점 N(0 ≤ N ≤ 100,000)에 있고, 동생은 점 K(0 ≤ K ≤ 100,000)에 있다. 수빈이는 걷거나 순간이동을 할 수 있다. 만약, 수빈이의 위치가 X일 때 걷는다면 1초 후에 X-1 또는 X+1로 이동하게 된다. 순간이동을 하는 경우에는 1초 후에 2*X의 위치로 이동하게 된다.

수빈이와 동생의 위치가 주어졌을 때, 수빈이가 동생을 찾을 수 있는 가장 빠른 시간이 몇 초 후인지 구하는 프로그램을 작성하시오.

입력

첫 번째 줄에 수빈이가 있는 위치 N과 동생이 있는 위치 K가 주어진다. N과 K는 정수이다.

출력

수빈이가 동생을 찾는 가장 빠른 시간을 출력한다.

 

예제 입력 1

5 17

예제 출력 

4

힌트

수빈이가 5-10-9-18-17 순으로 가면 4초만에 동생을 찾을 수 있다.

 

[문제 해설]

처음 생각했던 것은 다이나믹 프로그래밍이였다. 각각의 위치에 가는 시간을 배열에 저장해서 다이나믹 프로그래밍으로 풀려고 했으나 생각보다 어려웠던 것은 뒤로 가는 경우와 앞으로 가는 경우까지 생각해야되서 복잡했다. 

 

돌고 돌아 BFS로 풀게 되었다. 모든 장소를 0으로 초기화 시킨 배열 d도 준비한다. 출발점을 큐의 첫번째 원소로 먼저 넣는다. 그 점에서 -1, +1, *2 한 곳을 next로 두고 for문을 통해서 반복한다. next가 범위 안에 있고, d배열에서 방문하지 않은 0이면 d[next]는 d[v]+1값이 들어가고 next를 큐에 추가해준다. 그럼 n에서 k로 가는 최소점이 d배열에 들어가게 된다. 종료 조건은 큐에 k값이 들어간게 확인되었을때 d[v]를 출력해주고 종료하면 된다.

 

(나는 d배열에 어떤값이 들어가있는지 계속 헷갈려서 print로 찍어주었다. 주석은 무시하고 보면 된다_

from collections import deque
n, k = map(int, input().split())
# n에서 k로 가기
d=[0]*100001
def bfs(n):
    queue=deque()
    queue.append(n)
    while queue:
        v=queue.popleft()
        if v==k:
            print(d[v])
            return
        for next in (v-1,v+1,v*2):
            if 0<=next<100001 and not d[next]:
                # for i in range(20):
                #     print(d[i], end=' ')
                # print()
                d[next]=d[v]+1
                queue.append(next)

bfs(n)
728x90
반응형
728x90
반응형

www.acmicpc.net/problem/2108

 

2108번: 통계학

첫째 줄에 수의 개수 N(1 ≤ N ≤ 500,000)이 주어진다. 그 다음 N개의 줄에는 정수들이 주어진다. 입력되는 정수의 절댓값은 4,000을 넘지 않는다.

www.acmicpc.net

문제

수를 처리하는 것은 통계학에서 상당히 중요한 일이다. 통계학에서 N개의 수를 대표하는 기본 통계값에는 다음과 같은 것들이 있다. 단, N은 홀수라고 가정하자.

  1. 산술평균 : N개의 수들의 합을 N으로 나눈 값
  2. 중앙값 : N개의 수들을 증가하는 순서로 나열했을 경우 그 중앙에 위치하는 값
  3. 최빈값 : N개의 수들 중 가장 많이 나타나는 값
  4. 범위 : N개의 수들 중 최댓값과 최솟값의 차이

N개의 수가 주어졌을 때, 네 가지 기본 통계값을 구하는 프로그램을 작성하시오.

입력

첫째 줄에 수의 개수 N(1 ≤ N ≤ 500,000)이 주어진다. 그 다음 N개의 줄에는 정수들이 주어진다. 입력되는 정수의 절댓값은 4,000을 넘지 않는다.

출력

첫째 줄에는 산술평균을 출력한다. 소수점 이하 첫째 자리에서 반올림한 값을 출력한다.

둘째 줄에는 중앙값을 출력한다.

셋째 줄에는 최빈값을 출력한다. 여러 개 있을 때에는 최빈값 중 두 번째로 작은 값을 출력한다.

넷째 줄에는 범위를 출력한다.

예제 입력 1

5 1 3 8 -2 2

예제 출력 1

2 2 1 10

예제 입력 2

1 4000

예제 출력 2

4000 4000 4000 0

예제 입력 3

5 -1 -2 -3 -1 -2

예제 출력 3

-2 -2 -1 2

 

[문제 해설]

문제에서 구할 것이 꽤 많다. 평균, 중앙값, 최빈값, 최대값과 최솟값의 차이이다. 하나씩 해결해 나가면 된다.

먼저 1번부터 구해보자.

n = int(sys.stdin.readline())

datas=[]
for _ in range(n):
    datas.append(int(sys.stdin.readline()))

def first(datas):
    return round(sum(datas)/len(datas))

여기서 까다로운 점은 소수점 첫째 자리에서 반올림한 값을 출력해야된다는 것이다. round함수를 사용하자. round함수에서 두번째 인수를 생략하면 앞에 인자에 가장 가까운 정수를 출력한다. 소수 첫째자리에서 반올림하고 싶은 것을 해결해 줄 수 있다. 

 

2번은 중앙값을 출력하는 것이다. 중간 인덱스를 변수로 저장하여 풀면 된다.

def second(datas):
    datas.sort()
    mid = (len(datas))//2
    return datas[mid]

3번은 어떻게 풀지 감이 아예 오지 않았다. 배열을 2개씩 만들어서도 풀려고 했는데 계속 실패하였다. 

찾아보니 최빈값은 모듈을 이용해서 쉽게 해결할 수 있었다. 

 

collections모듈에서 Counter클래스를 사용하는 것이다. 데이터의 개수를 셀 때 파이썬의 collections모듈의 Counter클래스가 유용하다.

 

Counter클래스는 파이썬의 기본 자료구조인 사전형을 확장하고 있기 때문에, 사전에서 제공하는 API를 그대로 사용할 수 있다. Counter 클래스는 데이터의 개수가 많은 순으로 정렬된 배열을 리턴하는 most_common이라는 메서드를 제공하고 있기 때문에 최빈값을 구하는데 사용할 수가 있다.

 

from collections import Counter

Counter('hello world').most_common() 
# [('l', 3), ('o', 2), ('h', 1), ('e', 1), (' ', 1), ('w', 1), ('r', 1), ('d', 1)]

다음과 같이 많은 순서대로 리턴할 수 있다. 이것을 최밴값에 사용해보자.

 

from collections import Counter
def third(datas):
    mode_dict = Counter(datas)
    modes = mode_dict.most_common()

    if len(datas) > 1:
        if modes[0][1] == modes[1][1]:
            mod = modes[1][0]
        else:
            mod = modes[0][0]
    else:
        mod = modes[0][0]

    return mod

modes[0][1]은 datas에서 제일 많이 나온 값의 개수를 의미 한다. 최빈값이 여러 개일 경우 두번째로 작은 값을 출력하라고 했으니 modes[0][1] == modes[1][1]일때 modes[1][0]을 출력하고 그렇지 않을때는 modes[0][0]을 출력하면 된다.

 

4번은 최대값에서 최소값을 빼면 된다.

 

모든 코드는 아래와 같다.

from collections import Counter
import sys
n = int(sys.stdin.readline())

datas=[]
for _ in range(n):
    datas.append(int(sys.stdin.readline()))

def first(datas):
    return round(sum(datas)/len(datas))

def second(datas):
    datas.sort()
    mid = (len(datas))//2
    return datas[mid]

def third(datas):
    mode_dict = Counter(datas)
    modes = mode_dict.most_common()

    if len(datas) > 1:
        if modes[0][1] == modes[1][1]:
            mod = modes[1][0]
        else:
            mod = modes[0][0]
    else:
        mod = modes[0][0]

    return mod

def fourth(datas):
    return max(datas)-min(datas)

print(first(datas))
print(second(datas))
print(third(datas))
print(fourth(datas))
728x90
반응형

+ Recent posts