2023. 11. 11. 22:29ㆍ스터디
2주차 스터디 내용은 DFS, BFS를 집중적으로 학습했습니다.
LG전자 코딩테스트도 겹쳐있었던지라 집중적으로 이문제 저문제 풀어봤던 것 같습니다.
내용 및 설명 추가 예정
1. 백준 - 영역 구하기
from collections import deque
M,N,K = map(int,input().split())
A = [[0 for _ in range (0,N)] for _ in range (0,M)]
visited = [[False for _ in range (0,N)] for _ in range (0,M)]
for i in range (0,K): #벽(색칠된 부분) 체크하기
a = list(map(int,input().split()))
for j in range (a[1],a[3]):
for k in range (a[0],a[2]):
A[j][k] = 1
dx = [0,0,1,-1]
dy = [1,-1,0,0]
ans = []
for i in range (0,M):
for j in range (0,N):
if A[i][j] == 0 and visited[i][j] == False:
cnt = 1
deq = deque()
deq.appendleft((i,j))
while deq:
x,y = deq.popleft()
visited[x][y] = True
for k in range (0,4):
a = x + dx[k]
b = y + dy[k]
if 0 <= a < M and 0 <= b < N:
if A[a][b] == 1:
continue
if visited[a][b] == False and A[a][b] == 0:
deq.appendleft((a,b))
visited[a][b] = True
cnt += 1
ans.append(cnt)
ans.sort()
print(len(ans))
print(" ".join(str(s) for s in ans))
어떤 점의 좌표가 주어져있을 때, 그 점의 상하좌우를 전부 훑어보면서 방문한 곳인지 방문하지 않은 곳인지 체크하면서
deque에 추가해주면 됩니다. 방법은 dfs던 bfs던 상관 없을 것 같습니다.
처음으로 방문한 곳은 방문처리를 해서 이후에 올 수 없도록 하는 조치가 필요하겠습니다.
몇개가 붙어있는지 세면 되기 때문에, cnt를 통해 인접한 영역의 갯수를 구하면서 리스트 (ans)에 추가하면 되겠습니다.
ans를 오름차순으로 정렬해준 뒤, 출력해주면 되겠습니다.
2. 프로그래머스 - 미로 탐색
from collections import deque
def solution(maps):
answer = 0
dx = [-1, 1, 0, 0]
dy = [0, 0, -1, 1]
deq = deque()
deq.append((0, 0))
n = len(maps) #세로 길이 first component
m = len(maps[0]) #가로 길이 second component
check = [[False for _ in range (0,m)] for _ in range (0,n)]
while deq:
x,y = deq.popleft()
check[x][y] = True
for i in range(0,4):
a = x + dx[i]
b = y + dy[i]
if 0 <= a < n and 0 <= b < m:
if maps[a][b] == 0:
continue
else:
if check[a][b] == False:
maps[a][b] += maps[x][y]
check[a][b] = True
deq.append((a,b))
else:
maps[a][b] = min(maps[a][b], maps[x][y] + 1)
else:
continue
if maps[-1][-1] == 1:
return -1
else:
return maps[-1][-1]
N,M = map(int,input().split())
A = []
for i in range (0,N):
a = input()
b = []
for j in range (0,len(a)):
b.append(int(a[j]))
A.append(b)
print(solution(A))
동일하게 상하좌우로 막히지 않은 곳을 찾아가면서 도착점까지 가면 되겠습니다.
주의해야할 점은, 이미 방문한 포인트에 있어서는 어떻게 해야하는가? 가 되겠습니다.
그때는 기존값과 새롭게 취한 루트에 대해서의 값을 비교해주면 되겠습니다.
그리고 deque가 비워졌음에도 불구하고 도달하지 못한 경우에는 출구에 도달하지 못했다는 뜻이 되겠습니다.
3. 프로그래머스 - 무인도 여행
from collections import deque
def solution(maps):
answer = []
N = len(maps)
A = [[0 for _ in range (0,len(maps[0]))] for _ in range (0,N)]
for i in range (0,N):
for j in range (0,len(maps[0])):
if maps[i][j] == "X":
A[i][j] = "X"
else:
A[i][j] = int(maps[i][j])
M = len(maps[0])
visited = [[False for _ in range (0,M)] for _ in range (0,N)]
#first ex: n = 4, m = 5
dx = [0,0,1,-1]
dy = [1,-1,0,0]
for i in range (0,N):
for j in range (0,M):
if A[i][j] == "X" or visited[i][j] == True:
continue
else:
cnt = A[i][j]
deq = deque()
deq.appendleft((i,j))
while deq:
x,y = deq.popleft()
visited[x][y] = True
for k in range (0,4):
a = x + dx[k]
b = y + dy[k]
if 0 <= a < N and 0 <= b < M:
if visited[a][b] == False and A[a][b] != "X":
deq.appendleft((a,b))
visited[a][b] = True
cnt += A[a][b]
answer.append(cnt)
answer.sort()
if answer == []:
return [-1]
else:
return answer
1번과 동일한 유형입니다.
단순히 이 경우에는 각 좌표 (i,j)에 방문할때마다 cnt에 A_ij에 해당하는 값을 더해주면 됩니다.
이후, cnt 값을 리스트에 추가하면서 오름차순으로 정렬하면 정답이 나옵니다.
4. 프로그래머스 - 네트워크
from collections import deque
def solution(n, computers):
answer = 0
connection = []
for i in range (0,n):
a = []
deq = deque()
deq.append((i,i))
checked = [[False for _ in range (0,n)] for _ in range (0,n)]
checked[i][i] = True
a.append(i)
while deq:
x,y = deq.popleft()
a.append(y)
for z in range (0,n) :
if computers[y][z] == 1 and checked[y][z] == False:
deq.append((y,z))
checked[y][z] = True
a.append(z)
else:
continue
a = list(set(a))
connection.append(a)
ans = []
for i in range (0,len(connection)):
if connection[i] in ans:
continue
else:
ans.append(connection[i])
answer = len(ans)
return answer
이 경우에는 Directed graph가 아닌 Undirected Graph입니다.
예를 들어, i와 j가 연결되어있다 한다면 행렬을 만들 때 A_ij = A_ji = 1로서 설정하는 방식으로 행렬 A를 구성해줍니다.
이런 행렬 A를 Adjacency Matrix (인접행렬) 이라고 부릅니다.
결국 각 노드에 방문했을 때 이어져있는 모든 노드를 찾아보는 방식이 되겠습니다.
그렇게 노드의 끝이 어디인지 찾아가는 방식이 되겠네요.
(이 과정에서 연산이 조금 많아질 수 있는데, 이런 경우에는 처음에 A를 받아올 때,
A = [[] for _ in range (0,N)] 이렇게 빈 매트릭스를 만들어준 뒤에, A[i]에 대해서만 사이클을 돌려주면 될 것 같습니다.)
5. 백준 - 케빈 베이컨의 6단계 법칙
import sys
import math
input = sys.stdin.readline
N,M = map(int,input().split())
A = [[math.inf for _ in range (0,N)] for _ in range (0,N)]
for i in range (0,M):
a,b = map(int,input().split())
A[a-1][b-1],A[b-1][a-1] = 1,1
for k in range (0,N):
for i in range (0,N):
for j in range (0,N):
A[i][j] = min(A[i][j], A[i][k] + A[k][j])
answer = []
for i in range (0,N):
a = sum(A[i]) - A[i][i]
answer.append(a)
min_val = min(answer)
for i in range (0,N):
if answer[i] == min_val:
print(i+1)
break
위에서 언급한 Adjacency Matrix의 예 입니다.
친구라는 것이 단방향이 아니라 양방향으로 알고 있는 것을 전제로 하고 있기 때문에, 이렇게 생각해볼 수 있겠습니다.
한편, 행렬 2개를 곱해주면서 그 값이 어떻게 되는지 체크하는 것이겠습니다.
아이디어로서는 i와 j가 알고있고, j가 k가 알고 있다고 하는 상황에서, i와 k의 관계가 어떨까요?
(설명 조금 더 작성)
6. 백준 - 내리막 길 (골드 3)
def f(x,y):
if x == M-1 and y == N-1:
return 1
if dp[x][y] != -1:
return dp[x][y]
route = 0
dx = [0,0,1,-1]
dy = [1,-1,0,0]
for i in range (0,4):
a = x + dx[i]
b = y + dy[i]
if 0 <= a < M and 0 <= b < N and graph[x][y] > graph[a][b]:
route += f(a,b)
dp[x][y] = route
return route
M,N = map(int,input().split())
graph = []
dp = [[-1 for _ in range (0,N)] for _ in range (0,M)]
for i in range (0,M):
a = list(map(int,input().split()))
graph.append(a)
print(f(0,0))
7. Leet code - Rotting Oranges (medium)
class Solution:
import copy
from collections import deque
def orangesRotting(self, grid: List[List[int]]) -> int:
m = len(grid)
n = len(grid[0])
checked = [[False for _ in range (0,n)] for _ in range (0,m)]
deq = deque()
a = []
fresh = 0
for i in range (0,m):
for j in range (0,n):
if grid[i][j] == 1:
fresh += 1
if grid[i][j] == 2:
a.append([i,j])
deq.append(a)
dx = [0,0,1,-1]
dy = [1,-1,0,0]
day = 0
#이미 다 상해있는 경우
if fresh == 0:
return day
#그렇지 않은 경우
while deq:
k = fresh
x = deq.popleft()
rotten_orange = []
for i in range (0,len(x)):
for j in range (0,4):
a = x[i][0] + dx[j]
b = x[i][1] + dy[j]
if 0 <= a < m and 0 <= b < n and grid[a][b] == 1 :
grid[a][b] = 2
fresh -= 1
rotten_orange.append([a,b])
if k == 0:
break
if k == fresh:
return -1
else:
day += 1
deq.appendleft(rotten_orange)
return day
상한 오렌지는 상하좌우에 있는 오렌지를 전부 상하게 한다는 점에 착목하면 좋을 것 같습니다.
8. 프로그래머스 - 게임 맵 최단거리
from collections import deque
def solution(maps):
answer = 0
dx = [-1, 1, 0, 0]
dy = [0, 0, -1, 1]
deq = deque()
deq.append((0, 0))
n = len(maps) #세로 길이 first component
m = len(maps[0]) #가로 길이 second component
check = [[False for _ in range (0,m)] for _ in range (0,n)]
while deq:
x,y = deq.popleft()
check[x][y] = True
for i in range(0,4):
a = x + dx[i]
b = y + dy[i]
if 0 <= a < n and 0 <= b < m:
if maps[a][b] == 0:
continue
else:
if check[a][b] == False:
maps[a][b] += maps[x][y]
check[a][b] = True
deq.append((a,b))
else:
maps[a][b] = min(maps[a][b], maps[x][y] + 1)
else:
continue
if maps[-1][-1] == 1:
return -1
else:
return maps[-1][-1]
9. Leet code - Course Schedule (medium)
class Solution:
from collections import deque
def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
v = numCourses
e = len(prerequisites)
graph = [[] for _ in range (0,v)]
indegree = [0 for _ in range (0,v)]
for edge in prerequisites:
a,b = edge[0],edge[1]
graph[a].append(b)
indegree[b] += 1
deq = deque()
for i in range (0,v):
if indegree[i] == 0:
deq.appendleft(i)
result = []
print(deq)
if len(deq) == 0:
return False
A = []
while deq:
now = deq.popleft()
result.append(now)
for i in graph[now]:
indegree[i] -= 1
if indegree[i] == 0:
deq.appendleft(i)
if len(result) != v:
return False
return True
위상정렬 (Topological sort)에 대한 개념을 알 수 있었습니다.
일반적인 DFS, BFS와 비슷한 느낌이지만 directed graph를 설정한 후, Route의 끝까지 뚫는 역할을 합니다.
10. 백준 - 전쟁전투 (실버 1)
from collections import deque
N,M = map(int,input().split())
check = [[False for _ in range (0,N)] for _ in range (0,M)]
war = []
for i in range (0,M):
a = input()
war_list = []
for j in range (0,len(a)):
war_list.append(a[j])
war.append(war_list)
power1 = 0
power2 = 0
dx = [0,0,1,-1]
dy = [1,-1,0,0]
for i in range (0,M):
for j in range (0,N):
if war[i][j] == "W" and check[i][j] == False:
check[i][j] = True
deq = deque()
deq.append((i,j))
cnt = 0
while deq:
x,y = deq.popleft()
cnt += 1
for k in range (0,4):
a = x + dx[k]
b = y + dy[k]
if 0 <= a < M and 0 <= b < N and check[a][b] == False and war[a][b] == "W":
deq.append((a,b))
check[a][b] = True
power1 += cnt ** 2
if war[i][j] == "B" and check[i][j] == False:
check[i][j] = True
deq = deque()
deq.append((i,j))
cnt = 0
while deq:
x,y = deq.popleft()
cnt += 1
for k in range (0,4):
a = x + dx[k]
b = y + dy[k]
if 0 <= a < M and 0 <= b < N and check[a][b] == False and war[a][b] == "B":
deq.append((a,b))
check[a][b] = True
power2 += cnt ** 2
print(power1,power2)
11. 백준 - 숨바꼭질 2 (골드 5)
from collections import deque
N,K = map(int,input().split())
if N >= K:
print(N-K)
print(1)
else:
cnt = 0
num = [0 for _ in range (0,100001)]
deq = deque()
deq.appendleft([N])
while deq:
X = deq.popleft() #리스트로 받아옴
B = []
for i in range (0,len(X)):
for y in (X[i] - 1, X[i] + 1, 2 * X[i]):
if y > 100000 or y < 0:
pass
else:
if num[y] == 0 or num[y] == num[X[i]] + 1:
B.append(y)
if y == K:
cnt += 1
num[y] = num[X[i]] + 1
else:
if y == K:
cnt += 1
deq.appendleft(B)
if cnt != 0:
break
else:
continue
print(num[K])
print(cnt)
12. 프로그래머스 - 타겟 넘버
from collections import deque
def solution(numbers, target):
answer = 0
deq = deque()
deq.append([numbers[0],-numbers[0]])
cnt = 1
while cnt < len(numbers):
A = deq.popleft()
B = []
for i in range (0,len(A)):
B.append(A[i]-numbers[cnt])
B.append(A[i]+numbers[cnt])
deq.append(B)
cnt += 1
for i in range (0,len(deq[0])):
if deq[0][i] == target:
answer += 1
return answer
'스터디' 카테고리의 다른 글
[혼자 공부한] 분리집합 (0) | 2024.08.15 |
---|---|
4주차 스터디(23.12.01)-2 (1) | 2023.12.01 |
4주차 스터디(23.12.01) (1) | 2023.11.30 |
3주차 스터디(23.11.24) (0) | 2023.11.30 |
1주차 스터디(23.11.09) - 완전 탐색 (Brute Force) (0) | 2023.11.07 |