-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
59-xxubin04 #220
59-xxubin04 #220
Conversation
23학번이... 헌내기? |
23학번도 새내기로 쳐주나요? 아싸~~ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
처음엔 코드 간편하게 짤려고 재귀 기반 dfs 코드로 구현했는데, 속도가 엄청나게 느리네요...
recursion dfs
import sys
def main(input):
N, M = map(int, input().split())
campus = [[None] * M for _ in range(N)]
converter = {'O': 0, 'X': -1, 'I': 0, 'P': 1}
start_x, start_y = 0, 0
for i in range(N):
for j, info in enumerate(input().rstrip()):
if info == 'I':
start_x, start_y = i, j
campus[i][j] = converter[info]
def out_of_bound(x: int, y: int) -> bool:
return not (0 <= x < N and 0 <= y < M)
def dfs(x: int, y: int) -> int:
if out_of_bound(x, y) or campus[x][y] == -1:
return 0
is_human = (campus[x][y] == 1)
campus[x][y] = -1
return is_human + dfs(x - 1, y) + dfs(x, y + 1) + dfs(x + 1, y) + dfs(x, y - 1)
num = dfs(start_x, start_y)
print('TT' if num == 0 else num)
if __name__ == "__main__":
sys.setrecursionlimit(10**6)
main(sys.stdin.readline)
해서 queue 쓰는 bfs로 바꾸니까 속도가 확 빨라지네요...
queue bfs
from collections import deque
def bfs(campus: list, q: deque) -> int:
def out_of_bound(x: int, y: int) -> bool:
return not (0 <= x < N and 0 <= y < M)
num = 0
while q:
x, y = q.popleft()
for dx, dy in offset:
nx, ny = x + dx, y + dy
if out_of_bound(nx, ny) or campus[nx][ny] == -1:
continue
num += 1 if campus[nx][ny] == 1 else 0
campus[nx][ny] = -1
q.append((nx, ny))
return num
if __name__ == "__main__":
input = open(0).readline
N, M = map(int, input().split())
campus = [[None] * M for _ in range(N)]
converter = {'O': 0, 'X': -1, 'I': -1, 'P': 1}
offset = ((-1, 0), (0, 1), (1, 0), (0, -1))
q = deque()
for i in range(N):
for j, info in enumerate(input().rstrip()):
if info == 'I':
q.append((i, j))
campus[i][j] = converter[info]
ans = bfs(campus, q)
print('TT' if ans == 0 else ans)
설마? 하고 stack 쓰는 dfs로 하니까 셋 중 제일 빠르네요 ㅋㅋ
stack dfs
def dfs(campus: list, s: list) -> int:
def out_of_bound(x: int, y: int) -> bool:
return not (0 <= x < N and 0 <= y < M)
num = 0
while s:
x, y = s.pop()
for dx, dy in offset:
nx, ny = x + dx, y + dy
if out_of_bound(nx, ny) or campus[nx][ny] == -1:
continue
num += 1 if campus[nx][ny] == 1 else 0
campus[nx][ny] = -1
s.append((nx, ny))
return num
if __name__ == "__main__":
input = open(0).readline
N, M = map(int, input().split())
campus = [[None] * M for _ in range(N)]
converter = {'O': 0, 'X': -1, 'I': -1, 'P': 1}
offset = ((-1, 0), (0, 1), (1, 0), (0, -1))
s = []
for i in range(N):
for j, info in enumerate(input().rstrip()):
if info == 'I':
s.append((i, j))
campus[i][j] = converter[info]
ans = dfs(campus, s)
print('TT' if ans == 0 else ans)
재귀 코드가 가장 깔끔하긴 한데... 재귀 호출 횟수가 너무 많아서 확 느려진 게 아닐까 추측 중입니다...
people = 0 | ||
visited = [[0 for _ in range(M)] for _ in range(N)] | ||
|
||
def bfs(graph, node_x, node_y, visited): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bfs가 아니라 dfs!
if "I" in row: | ||
row_I = i | ||
|
||
bfs(campus, row_I, campus[row_I].index("I"), visited) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
개인적인 생각으론 row_I
를 찾을 때 도연의 y 좌표도 구해놓는 게 좀 더 괜찮지 않을까 싶네요 :)
dx = [-1, 1, 0, 0] | ||
dy = [0, 0, -1, 1] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dx, dy 선언은 함수 밖으로 빼도 괜찮을 것 같아요. 지금 방식은 재귀 호출을 할 때마다 새로 정의되네요.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
흡;;; 문제 제목이 마음에 안듭니다... 개인적으로 찔리거나 그렇지는 않구요..크흡...
파이썬은 재귀사용할 때, 런탐에러 주의해야해서 sys 설정을 넣어줘야하는걸 깜빡했습니다, ㅎ 5분 어버버 댔네요
import sys
sys.setrecursionlimit(10**6)
input = sys.stdin.readline
def can_go(nx, ny):
return 0<=nx<n and 0<=ny<m and not visited[nx][ny]
def dfs(x,y):
global cnt
visited[x][y] = True
if graph[x][y] == 'P':
cnt+=1
for i in range(4):
nx = x + dx[i]
ny = y + dy[i]
if can_go(nx, ny):
if graph[nx][ny] !="X":
dfs(nx,ny)
dx = [-1,1,0,0]
dy = [0,0,-1,1]
cnt = 0
n,m = map(int,input().split())
graph = list(input() for _ in range(n))
visited = [[False]*m for _ in range(n)]
for i in range(n):
for j in range(m):
if graph[i][j]=="I":
dfs(i,j)
if cnt == 0:
print("TT") # 친구 없다고 코드로 놀리네요 ㅠ
else:
print(cnt)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
항상 bfs 쓰려다가 dfs써서... 이번에는 bfs로 풀어봤습니다!
visited로 따로 체크하지 않고, 문자열을 숫자로 바꾸어 배열에 넣었는데...
괜히 전체를 한 번 지나야하는게 주어진 값이 커지면 안 좋을 것 같다는 생각이 드네요...
다음에는 visited로 해보겠습니다!
전체 코드
input = open("input.txt").readline
from collections import deque
h, w = map(int,input().split())
campus = []
offset = [(-1, 0), (0, 1), (1, 0), (0, -1)]
dq = deque([])
answer = 0
for x in range(h):
row = []
for y, i in enumerate(input().rstrip()):
if i == "O":
row.append(0)
elif i =="P":
row.append(1)
elif i =="X":
row.append(2)
else:
row.append(3)
dq.append((x, y))
campus.append(row)
while dq:
nx, ny = dq.popleft()
for dx, dy in offset:
px = nx + dx
py = ny + dy
if px < 0 or px >= h or py < 0 or py >= w:
continue
if campus[px][py] > 1:
continue
elif campus[px][py] == 1:
answer += 1
campus[px][py] = 2
dq.append((px, py))
print(answer if not answer==0 else "TT")
🔗 문제 링크
백준 21736번: 헌내기는 친구가 필요해
✔️ 소요된 시간
40분
✨ 수도 코드
1. 문제 이해
I
: 도연이의 현재 위치P
: 사람의 위치O
: 빈 공간 (도연이가 움직일 수 있는 위치)X
: 벽 (도연이가 갈 수 없는 위치)전형적인 BFS 문제이다. 도연이가 만날 수 있는 사람의 수를 구하면 된다.
2. 코드 분석
캠퍼스의 크기인 N과 M을 입력받고, 캠퍼스의 정보들을 campus에 저장한다.
캠퍼스 내부에서 방문한 적이 없는 좌표라면 방문처리를 해준다.
그리고 해당 좌표에서 동서남북 좌표의 존재성과 방문여부를 확인해준다.
P
라면, people에 1을 더하고,(만날 수 있는 사람 수 1 추가) bfs 함수를 호출해준다.O
라면, 그저 이동할 수 있는 좌표인 것이므로 bfs 함수를 호출해준다.N만큼 캠퍼스의 정보를 입력받고, 입력받은 정보에서
I
가 등장하면 그 위치를row_I
로 저장해둔다.I
는 초기의 도연이의 위치이므로bfs(campus, row_I, campus[row_I].index("I"), visited)
으로 시작해준다.people이 0이라면 "TT"를 출력하고, 아니라면 people을 출력한다.
3. 전체 코드
📚 새롭게 알게된 내용
문제 제목이 딱 제 얘기같아서 풀게 되었습니다😁