컬쥐네 다락방
2021.03.10 TIL 알고리즘 공부 본문
2021.03.10 배운 지식
-DFS (깊이 우선 탐색)
-BFS (너비 우선 탐색)
어제 저녁부터 계속 붙잡고 있었던 DFS, BFS !
9일 밤 늦게까지 꼭 한 문제를 완성시키고 자겠다는 마음으로 시도했지만 자기 전까지 완성하지 못했다.. 🤬
그런데 다음날 아침에 처음부터 다시 코딩했더니 한번에 완성됐다!! (왜.. ????!!)
DFS 와 BFS는 한 노드를 시작으로 인접한 다른 노드로 재귀적 탐색을 거치는 방법을 말하는데, 대표적인 예시로 알파고가 있다. 알파고는 대국을 진행하면서 발생하는 모든 수를 계산하고 최적의 수를 찾아내기 때문!
DFS는 한 방향으로 끝까지 파고들고 끝을 확인한 후에 가지 않은 길로 다시 가는 순서로 탐색을 진행.
BFS는 갈라진 모든 경우의 수를 탐색하며 거미줄처럼 퍼지는 순서로 탐색을 진행.
이 방식을 연습해보기 위해 백준 알고리즘 문제 2606번과 7576번을 코딩해봤다!
처음 접하는 지식이라 유튜브와 강의 자료로 오랫동안 공부했고, 코딩도 많은 시간이 필요했다 😢
https://www.acmicpc.net/problem/2606
2606번: 바이러스
첫째 줄에는 컴퓨터의 수가 주어진다. 컴퓨터의 수는 100 이하이고 각 컴퓨터에는 1번 부터 차례대로 번호가 매겨진다. 둘째 줄에는 네트워크 상에서 직접 연결되어 있는 컴퓨터 쌍의 수가 주어
www.acmicpc.net
# 알고리즘 공부 #01
# 백준 2606
import sys
from collections import deque
def line_up(): #입력받은 컴퓨터의 연결고리들을 하나로 모아주는 함수
global com_lined
while temp_q : #먼저 들어온 순서대로 POPLEFT를 이용해 pop해주면서 끝날때까지 진행
x,y = temp_q.popleft(); #컴퓨터 별로 연결고리를 1개씩 입력하는 문제라서
if y not in com_lined[x]: #x,y로 나눠서 각각 해당하는 컴퓨터의 연결 고리에
com_lined[x].append(y); # 상대가 포함되어 있는지 확인하고 없으면 넣어주도록 했다.
if x not in com_lined[y]:
com_lined[y].append(x);
return
def virus(start_com): #다음엔 바이러스가 퍼지도록 구현한 함수
global com_lined
global com_status
for i in com_lined[start_com]: #시작되는 지점을 지정해주고
if com_status[i] == 0: #그 컴퓨터와 연결된 모든 컴퓨터들을 하나씩 돌아가면서 확인
com_status[i] = 1; #해당 컴퓨터가 바이러스에 감염되지않았다면
virus(i) #컴퓨터 상태를 감염되었다고 바꿔주고 해당 컴퓨터 번호를
else: #다시 바이러스가 퍼지도록 재귀함수로 구현했다.
continue
return
com_num = int(sys.stdin.readline());
line_num = int(sys.stdin.readline());
lines = [list(map(int, sys.stdin.readline().split())) for _ in range(line_num)];
com_lined = [list() for _ in range(0,com_num+1)];
com_status = [0]*(com_num+1)
cnt = 0;
temp_q = deque(lines)
start_com = 1;
com_status[1] = 1;
line_up();
virus(1);
for i in com_status:
if i == 1:
cnt += 1
print(cnt-1);
사실 입력하는 방식이 굉장히 단순해서 차례 차례 검사를 진행해도 간단히 출력을 나타냈을 것 같은데, 내가 공부한 DFS,BFS의 방식을 구현해보고 싶어서 입력받은 연결 고리들을 하나씩 정리해서 각 컴퓨터에 연결된 컴퓨터가 한번에 보이도록 line_up 함수를 만들어봤다.
내가 원하는 대로 구현이 되서 기분 좋았다 !
다음은 7576번
https://www.acmicpc.net/problem/7576
7576번: 토마토
첫 줄에는 상자의 크기를 나타내는 두 정수 M,N이 주어진다. M은 상자의 가로 칸의 수, N은 상자의 세로 칸의 수를 나타낸다. 단, 2 ≤ M,N ≤ 1,000 이다. 둘째 줄부터는 하나의 상자에 저장된 토마토
www.acmicpc.net
# 알고리즘 공부 #01
# 백준 7576
import sys
from collections import deque
#익은 토마토의 위치를 찾아 큐에 넣어주기
def find_start(t_width,t_height,lines):
global temp_q
for i in range(0,t_height):
for j in range(0,t_width):
if lines[i][j] == 1:
start= [i,j];
temp_q.append(start);
return
#토마토가 익어 가는 함수
def go_tomato():
while temp_q: #큐에 익은 토마토 시작 지점이 없어질때까지
x,y = temp_q.popleft() #토마토 위치 가져오기
for i in range(4): #익은 토마토 위치 기준 4방향 확인
next_x = x + x_move[i];
next_y = y + y_move[i];
if 0<= next_x < t_height and 0<= next_y < t_width : #토마토 상자를 벗어나지 않아야함
if lines[next_x][next_y] == 0 or lines[next_x][next_y] > lines[x][y] +1 : #익지 않았으면 혹은 이 루트가 더 빨리 익으면
lines[next_x][next_y] = lines[x][y] +1; #영향을 준 토마토의 날짜에 1을 더해서 값을 변경
temp_q.append([next_x,next_y]) #이번에 익은 토마토의 위치를 큐에 저장
return
x_move = [0,0,-1,1] #4방향 확인을 위해 설정함
y_move = [-1,1,0,0]
t_width,t_height = map(int, sys.stdin.readline().split()); #토마토 상자의 폭과 너비
#토마토 정보를 받기
lines = [list(map(int, sys.stdin.readline().split())) for _ in range(t_height)];
start = []
temp_q = deque() #popleft를 사용하기 위해 deque 사용
find_start(t_width,t_height,lines); #익은 토마토 위치 확인
if temp_q == False : #익은 토마토가 없으면 0을 출력
print(0)
else :
go_tomato() #토마토를 익히기
day = max(map(max,lines)) -1 #첫날 익은 토마토의 시작 값이 1이었기때문에 제일 오래 걸린 날짜에서 -1
for i in range(0,t_height): #익지 않은 토마토가 있으면 -1을 출력하고 종료
for j in range(0,t_width):
if lines[i][j] == 0:
print(-1)
exit()
print(day) #모두 익었으면 걸린 날짜를 출력
처음에는 하루하루 토마토가 익어가고 이를 카운트해서 마지막에 걸린 day를 출력하고 싶었는데,
자꾸만 에러가 나서 아에 처음 입력했던 토마토들의 상태를 day로 사용해버렸다.
만약 빈 칸을 나타내는게 -1이 아니라 2 였다면 이 방식은 사용하기 어려울듯.. 🤔
그래도 숫자가 점점 퍼지면서 토마토가 익어가고 걸린 day를 출력하는게 귀여웠다.
갈수록 내가 모르는 지식들이 나오니까 공부하는 시간도 오래걸리고 응용하기도 어려워지는 것 같다..
내일 동적 계획법까지 끝내면 문제 은행식으로 일주일간 배웠던 개념들을 계속 사용하는 시간이 온다.
반복해서 사용하면서 내 지식으로 만드는 방법이 최선일듯..
화이팅 !!
'공부방 > 코드 정리' 카테고리의 다른 글
2021.03.19 TIL 알고리즘 공부 (0) | 2021.03.19 |
---|---|
2021.03.15 TLI 알고리즘 공부 (0) | 2021.03.15 |
2021.03.09 TIL 알고리즘 공부 (0) | 2021.03.10 |