문제 <경쟁적 전염>
NxN 크기의 시험관이 있다. 시험관은 1x1 크기의 칸으로 나누어지며, 특정한 위치에는 바이러스가 존재할 수 있다. 모든 바이러스는 1번부터 K번까지의 바이러스 종류 중 하나에 속한다.
시험관에 존재하는 모든 바이러스는 1초마다 상, 하, 좌, 우의 방향으로 증식해 나간다. 단, 매 초마다 번호가 낮은 종류의 바이러스부터 먼저 증식한다. 또한 증식 과정에서 특정한 칸에 이미 어떠한 바이러스가 존재한다면, 그 곳에는 다른 바이러스가 들어갈 수 없다.
시험관의 크기와 바이러스의 위치 정보가 주어졌을 때, S초가 지난 후에 (X,Y)에 존재하는 바이러스의 종류를 출력하는 프로그램을 작성하시오. 만약 S초가 지난 후에 해당 위치에 바이러스가 존재하지 않는다면, 0을 출력한다. 이 때 X와 Y는 각각 행과 열의 위치를 의미하며, 시험관의 가장 왼쪽 위에 해당하는 곳은 (1,1)에 해당한다.
예를 들어 다음과 같이 3x3 크기의 시험관이 있다고 하자. 서로 다른 1번, 2번, 3번 바이러스가 각각 (1,1), (1,3), (3,1)에 위치해 있다. 이 때 2초가 지난 뒤에 (3,2)에 존재하는 바이러스의 종류를 계산해보자.
입력
- 첫째 줄에 자연수 N, K가 공백을 기준으로 구분되어 주어진다. (1 ≤ N ≤ 200, 1 ≤ K ≤ 1,000)
- 둘째 줄부터 N개의 줄에 걸쳐서 시험관의 정보가 주어진다.
- 각 행은 N개의 원소로 구성되며, 해당 위치에 존재하는 바이러스의 번호가 공백을 기준으로 구분되어 주어진다.
- 단, 해당 위치에 바이러스가 존재하지 않는 경우 0이 주어진다.
- 또한 모든 바이러스의 번호는 K이하의 자연수로만 주어진다.
- N+2번째 줄에는 S, X, Y가 공백을 기준으로 구분되어 주어진다. (0 ≤ S ≤ 10,000, 1 ≤ X, Y ≤ N)
출력
- S초 뒤에 (X,Y)에 존재하는 바이러스의 종류를 출력한다.
- 만약 S초 뒤에 해당 위치에 바이러스가 존재하지 않는다면, 0을 출력한다.
풀이
- 시간에 따라 번호가 낮은 바이러스부터 증식되기 때문에 S초 동안 바이러스들을 차례로 증식하는 코드를 짜는 데에 초점을 두었다.
- 아래의 코드를 짤 때 바이러스가 증식된 곳을 시간이 지남에 따라 추가해주는 작업이 필요해, result라는 새로운 리스트를 만들어 해당 바이러스 번호의 증식이 끝난 뒤 추가해 주었다.
import sys
from collections import deque
input = sys.stdin.readline
N, M, K, X = map(int, input().split())
road = [[] for _ in range(N+1)]
import sys
input = sys.stdin.readline
N, K = map(int, input().split())
ex = [list(map(int, input().split())) for _ in range(N)]
virus = [[] for i in range(K + 1)]
for i in range(N):
for j in range(N):
if ex[i][j] != 0:
virus[ex[i][j]].append([i, j])
S, X, Y = map(int, input().split())
dx = [0, 0, -1, 1]
dy = [-1, 1, 0, 0]
def bfs(x, y):
for i in range(S):
for v in range(len(virus)):
result = [] # 바이러스가 퍼진 곳
for x, y in virus[v]: # 번호가 낮은 종류의 바이러스부터
v = ex[x][y] # 해당 지점의 바이러스
for i in range(4):
nx = x + dx[i]
ny = y + dy[i]
if 0 <= nx < N and 0 <= ny < N and ex[nx][ny] == 0: # 바이러스가 존재하지 않는 곳일 때
ex[nx][ny] = v # 바이러스 증식
result.append([nx, ny]) # 바이러스가 퍼진 곳 추가하기
if nx == X-1 and ny == Y-1: # (X, Y)까지 바이러스가 증식됐다면
return
for j in range(len(result)):
virus[v].append([result[j][0], result[j][1]]) # 바이러스가 퍼진 곳을 해당 바이러스 인덱스에 추가
bfs(X, Y)
print(ex[X - 1][Y - 1])
시간 초과 없이 문제는 해결했지만 for 문을 무분별하게 사용한 경향이 있어 다른 방법으로 문제를 풀어보았다.
사람들의 풀이를 참고해 본 결과, 바이러스의 번호와 좌표 그리고 시간을 함께 저장했다.
이 방법은 두 가지 모두 해결 가능하였다.
- 번호가 낮은 바이러스부터 순서대로 증식
- 1초가 지남에 따라 증식된 바이러스의 증식
결론적으로, 하나의 바이러스가 증식하면 해당 좌표의 바이러스는 증식에 영향을 주지 않는다
는 것을 인지하지 못했다.
따라서 이전 코드를 보면 매번 해당 바이러스 번호의 좌표 모두에서 증식이 이루어지는데, 증식된 바이러스에 한해서만 증식을 하면 되었다.
import sys
from collections import deque
input = sys.stdin.readline
N, K = map(int, input().split())
ex = [list(map(int, input().split())) for _ in range(N)]
virus = []
for i in range(N):
for j in range(N):
if ex[i][j] != 0:
virus.append((ex[i][j], i, j, 0)) # 바이러스 번호, 좌표(x, y), 시간 저장
S, X, Y = map(int, input().split())
dx = [0, 0, -1, 1]
dy = [-1, 1, 0, 0]
virus.sort()
q = deque(virus)
while q:
v, x, y, t = q.popleft() # 큐에서 꺼내기
if t == S: # S초가 지난 후라면
break
for i in range(4): # 상 하 좌 우
nx = x + dx[i]
ny = y + dy[i]
if 0 <= nx < N and 0 <= ny < N and ex[nx][ny] == 0: # 바이러스가 존재하지 않는 곳일 때
ex[nx][ny] = v # 바이러스 증식
q.append((v, nx, ny, t+1)) # 시간 + 1 해서 큐에 저장
if nx == X-1 and ny == Y-1: # 해당 위치 (X, Y)에 바이러스가 증식했다면 빠져 나오기(이 코드의 효율성은!?)
break
print(ex[X-1][Y-1])
이 문제에서 큐를 이용하여 해결하기 힘들 것 같았지만, 처음 생각이 잘못되었다는 것을 알 수 있었다.
문제를 조금 더 잘 파악했다면 큐를 이용해 문제를 풀 수 있었을텐데 아쉬웠다.
문제를 파악한 정도에 따라 문제를 푸는 방식이 달라지므로 조금만 더 생각하고 문제를 풀어야겠다.
코드의 효율성을 높이기 위해 리스트 대신 큐, 스택 등 다른 형태를 사용하는 습관을 기르자!
18405번: 경쟁적 전염
첫째 줄에 자연수 N, K가 공백을 기준으로 구분되어 주어진다. (1 ≤ N ≤ 200, 1 ≤ K ≤ 1,000) 둘째 줄부터 N개의 줄에 걸쳐서 시험관의 정보가 주어진다. 각 행은 N개의 원소로 구성되며, 해당 위치
www.acmicpc.net
'CS > 알고리즘' 카테고리의 다른 글
Python 집합(Set) 자료형 (0) | 2023.03.16 |
---|---|
[이코테] DFS&BFS - 블록 이동하기 (0) | 2023.03.15 |
DFS & BFS (0) | 2023.03.03 |
[이코테] 구현 - 외벽 점검 (0) | 2023.03.01 |
[이코테] 구현 - 자물쇠와 열쇠 (0) | 2023.03.01 |
문제 <경쟁적 전염>
NxN 크기의 시험관이 있다. 시험관은 1x1 크기의 칸으로 나누어지며, 특정한 위치에는 바이러스가 존재할 수 있다. 모든 바이러스는 1번부터 K번까지의 바이러스 종류 중 하나에 속한다.
시험관에 존재하는 모든 바이러스는 1초마다 상, 하, 좌, 우의 방향으로 증식해 나간다. 단, 매 초마다 번호가 낮은 종류의 바이러스부터 먼저 증식한다. 또한 증식 과정에서 특정한 칸에 이미 어떠한 바이러스가 존재한다면, 그 곳에는 다른 바이러스가 들어갈 수 없다.
시험관의 크기와 바이러스의 위치 정보가 주어졌을 때, S초가 지난 후에 (X,Y)에 존재하는 바이러스의 종류를 출력하는 프로그램을 작성하시오. 만약 S초가 지난 후에 해당 위치에 바이러스가 존재하지 않는다면, 0을 출력한다. 이 때 X와 Y는 각각 행과 열의 위치를 의미하며, 시험관의 가장 왼쪽 위에 해당하는 곳은 (1,1)에 해당한다.
예를 들어 다음과 같이 3x3 크기의 시험관이 있다고 하자. 서로 다른 1번, 2번, 3번 바이러스가 각각 (1,1), (1,3), (3,1)에 위치해 있다. 이 때 2초가 지난 뒤에 (3,2)에 존재하는 바이러스의 종류를 계산해보자.
입력
- 첫째 줄에 자연수 N, K가 공백을 기준으로 구분되어 주어진다. (1 ≤ N ≤ 200, 1 ≤ K ≤ 1,000)
- 둘째 줄부터 N개의 줄에 걸쳐서 시험관의 정보가 주어진다.
- 각 행은 N개의 원소로 구성되며, 해당 위치에 존재하는 바이러스의 번호가 공백을 기준으로 구분되어 주어진다.
- 단, 해당 위치에 바이러스가 존재하지 않는 경우 0이 주어진다.
- 또한 모든 바이러스의 번호는 K이하의 자연수로만 주어진다.
- N+2번째 줄에는 S, X, Y가 공백을 기준으로 구분되어 주어진다. (0 ≤ S ≤ 10,000, 1 ≤ X, Y ≤ N)
출력
- S초 뒤에 (X,Y)에 존재하는 바이러스의 종류를 출력한다.
- 만약 S초 뒤에 해당 위치에 바이러스가 존재하지 않는다면, 0을 출력한다.
풀이
- 시간에 따라 번호가 낮은 바이러스부터 증식되기 때문에 S초 동안 바이러스들을 차례로 증식하는 코드를 짜는 데에 초점을 두었다.
- 아래의 코드를 짤 때 바이러스가 증식된 곳을 시간이 지남에 따라 추가해주는 작업이 필요해, result라는 새로운 리스트를 만들어 해당 바이러스 번호의 증식이 끝난 뒤 추가해 주었다.
import sys
from collections import deque
input = sys.stdin.readline
N, M, K, X = map(int, input().split())
road = [[] for _ in range(N+1)]
import sys
input = sys.stdin.readline
N, K = map(int, input().split())
ex = [list(map(int, input().split())) for _ in range(N)]
virus = [[] for i in range(K + 1)]
for i in range(N):
for j in range(N):
if ex[i][j] != 0:
virus[ex[i][j]].append([i, j])
S, X, Y = map(int, input().split())
dx = [0, 0, -1, 1]
dy = [-1, 1, 0, 0]
def bfs(x, y):
for i in range(S):
for v in range(len(virus)):
result = [] # 바이러스가 퍼진 곳
for x, y in virus[v]: # 번호가 낮은 종류의 바이러스부터
v = ex[x][y] # 해당 지점의 바이러스
for i in range(4):
nx = x + dx[i]
ny = y + dy[i]
if 0 <= nx < N and 0 <= ny < N and ex[nx][ny] == 0: # 바이러스가 존재하지 않는 곳일 때
ex[nx][ny] = v # 바이러스 증식
result.append([nx, ny]) # 바이러스가 퍼진 곳 추가하기
if nx == X-1 and ny == Y-1: # (X, Y)까지 바이러스가 증식됐다면
return
for j in range(len(result)):
virus[v].append([result[j][0], result[j][1]]) # 바이러스가 퍼진 곳을 해당 바이러스 인덱스에 추가
bfs(X, Y)
print(ex[X - 1][Y - 1])
시간 초과 없이 문제는 해결했지만 for 문을 무분별하게 사용한 경향이 있어 다른 방법으로 문제를 풀어보았다.
사람들의 풀이를 참고해 본 결과, 바이러스의 번호와 좌표 그리고 시간을 함께 저장했다.
이 방법은 두 가지 모두 해결 가능하였다.
- 번호가 낮은 바이러스부터 순서대로 증식
- 1초가 지남에 따라 증식된 바이러스의 증식
결론적으로, 하나의 바이러스가 증식하면 해당 좌표의 바이러스는 증식에 영향을 주지 않는다
는 것을 인지하지 못했다.
따라서 이전 코드를 보면 매번 해당 바이러스 번호의 좌표 모두에서 증식이 이루어지는데, 증식된 바이러스에 한해서만 증식을 하면 되었다.
import sys
from collections import deque
input = sys.stdin.readline
N, K = map(int, input().split())
ex = [list(map(int, input().split())) for _ in range(N)]
virus = []
for i in range(N):
for j in range(N):
if ex[i][j] != 0:
virus.append((ex[i][j], i, j, 0)) # 바이러스 번호, 좌표(x, y), 시간 저장
S, X, Y = map(int, input().split())
dx = [0, 0, -1, 1]
dy = [-1, 1, 0, 0]
virus.sort()
q = deque(virus)
while q:
v, x, y, t = q.popleft() # 큐에서 꺼내기
if t == S: # S초가 지난 후라면
break
for i in range(4): # 상 하 좌 우
nx = x + dx[i]
ny = y + dy[i]
if 0 <= nx < N and 0 <= ny < N and ex[nx][ny] == 0: # 바이러스가 존재하지 않는 곳일 때
ex[nx][ny] = v # 바이러스 증식
q.append((v, nx, ny, t+1)) # 시간 + 1 해서 큐에 저장
if nx == X-1 and ny == Y-1: # 해당 위치 (X, Y)에 바이러스가 증식했다면 빠져 나오기(이 코드의 효율성은!?)
break
print(ex[X-1][Y-1])
이 문제에서 큐를 이용하여 해결하기 힘들 것 같았지만, 처음 생각이 잘못되었다는 것을 알 수 있었다.
문제를 조금 더 잘 파악했다면 큐를 이용해 문제를 풀 수 있었을텐데 아쉬웠다.
문제를 파악한 정도에 따라 문제를 푸는 방식이 달라지므로 조금만 더 생각하고 문제를 풀어야겠다.
코드의 효율성을 높이기 위해 리스트 대신 큐, 스택 등 다른 형태를 사용하는 습관을 기르자!
18405번: 경쟁적 전염
첫째 줄에 자연수 N, K가 공백을 기준으로 구분되어 주어진다. (1 ≤ N ≤ 200, 1 ≤ K ≤ 1,000) 둘째 줄부터 N개의 줄에 걸쳐서 시험관의 정보가 주어진다. 각 행은 N개의 원소로 구성되며, 해당 위치
www.acmicpc.net
'CS > 알고리즘' 카테고리의 다른 글
Python 집합(Set) 자료형 (0) | 2023.03.16 |
---|---|
[이코테] DFS&BFS - 블록 이동하기 (0) | 2023.03.15 |
DFS & BFS (0) | 2023.03.03 |
[이코테] 구현 - 외벽 점검 (0) | 2023.03.01 |
[이코테] 구현 - 자물쇠와 열쇠 (0) | 2023.03.01 |