기본기를 다지기 위한 드릴 루틴으로 사용하는 문제들이다.
총 8개로 각 문제의 주제는 다음과 같다.
1. DFS와 BFS
2. 퀵정렬
3. 이진탐색
4. 다익스트라
5. 플로이드 워셜
6. 서로소 집합
7. 크루스칼
8. 위상정렬
문제 링크와 정답 코드
1. DFS와 BFS
https://www.acmicpc.net/problem/1260
1260번: DFS와 BFS
첫째 줄에 정점의 개수 N(1 ≤ N ≤ 1,000), 간선의 개수 M(1 ≤ M ≤ 10,000), 탐색을 시작할 정점의 번호 V가 주어진다. 다음 M개의 줄에는 간선이 연결하는 두 정점의 번호가 주어진다. 어떤 두 정점 사
www.acmicpc.net
from collections import deque
input_n, input_m, input_v = map(int,input().split())
graph_list=[[] for _ in range(input_n+1)]
for i in range(input_m):
node1, node2 = map(int, input().split())
target_idx=0
while target_idx<len(graph_list[node1]):
if graph_list[node1][target_idx]>=node2: break
target_idx+=1
graph_list[node1]=graph_list[node1][:target_idx] + [node2] + graph_list[node1][target_idx:]
target_idx=0
while target_idx<len(graph_list[node2]):
if graph_list[node2][target_idx]>=node1: break
target_idx+=1
graph_list[node2]=graph_list[node2][:target_idx] + [node1] + graph_list[node2][target_idx:]
dfs_history=[]
bfs_history=[]
def dfs(graph, v, visited):
global dfs_history
visited[v]= True
dfs_history.append(v)
for i in graph[v]:
if not visited[i]:
dfs(graph, i, visited)
def bfs(graph, v, visited):
global bfs_history
visited[v]=True
queue=deque([v])
while queue:
cur_node=queue.popleft()
bfs_history.append(cur_node)
for i in graph[cur_node]:
if not visited[i]:
queue.append(i)
visited[i]=True
dfs(graph_list, input_v, [False for _ in range(input_n+1)])
bfs(graph_list, input_v, [False for _ in range(input_n+1)])
for i in dfs_history:
print("%d "%i, end="")
print()
for i in bfs_history:
print("%d "%i, end="")
간선 정보를 인접 리스트에 담을 때, 오름차순으로 담기 위해 선형탐색 알고리즘이 포함되었다.
이부분을 이진탐색을 활용하거나 힙 자료형을 활용하는 방식으로 개선 가능하다.
2. 퀵정렬
https://www.acmicpc.net/problem/2750
2750번: 수 정렬하기
첫째 줄에 수의 개수 N(1 ≤ N ≤ 1,000)이 주어진다. 둘째 줄부터 N개의 줄에는 수 주어진다. 이 수는 절댓값이 1,000보다 작거나 같은 정수이다. 수는 중복되지 않는다.
www.acmicpc.net
import sys
sys.setrecursionlimit(15000)
input_n=int(input())
li=[]
for i in range(input_n):
li.append(int(input()))
def QuickSort(array, start, end):
if start>=end: return
pivot=start
left=start+1
right=end
while left<=right:
while left<=end and array[left]<=array[pivot]:
left+=1
while right>start and array[right]>=array[pivot]:
right-=1
if right<left:
array[right], array[pivot]=array[pivot], array[right]
else:
array[left],array[right]=array[right], array[left]
QuickSort(array,start,right-1)
QuickSort(array,right+1,end)
QuickSort(li, 0, len(li)-1)
for i in li:
print(i)
재귀 제한을 풀어주어야 한다.
부등호에서 등호의 포함 여부, 조건의 순서 등 신경 쓸 부분이 많은 코드이니 주의하자.
또한 연습때 left와 start, right와 end를 혼동하여 쓰는 실수가 있었으니 주의하자.
3. 이진탐색
https://www.acmicpc.net/problem/1920
1920번: 수 찾기
첫째 줄에 자연수 N(1 ≤ N ≤ 100,000)이 주어진다. 다음 줄에는 N개의 정수 A[1], A[2], …, A[N]이 주어진다. 다음 줄에는 M(1 ≤ M ≤ 100,000)이 주어진다. 다음 줄에는 M개의 수들이 주어지는데, 이 수들
www.acmicpc.net
def Binary_Search(array, target, start, end):
while start<=end:
#print("looping..")
mid = (start+end)//2
if array[mid]==target:
return mid
elif target<array[mid]:
end=mid-1
else:
start=mid+1
return None
N=int(input())
array=list(map(int,input().split()))
array.sort()
M=int(input())
targets=list(map(int,input().split()))
for i in range(M):
if Binary_Search(array, targets[i], 0, N-1) == None:
print(0)
else:
print(1)
마찬가지로 부등호에 주의하자.
연습용 문제의 경우 입력받은 리스트를 정렬해야하는데, 예시코드에서는 맘편히 리스트의 sort 메서드를 사용했다.
퀵정렬까지 한번에 연습하고싶으면 퀵정렬 알고리즘을 구현해서 사용해도 연습에 좋을것이다.
4. 다익스트라
https://www.acmicpc.net/problem/1753
1753번: 최단경로
첫째 줄에 정점의 개수 V와 간선의 개수 E가 주어진다. (1 ≤ V ≤ 20,000, 1 ≤ E ≤ 300,000) 모든 정점에는 1부터 V까지 번호가 매겨져 있다고 가정한다. 둘째 줄에는 시작 정점의 번호 K(1 ≤ K ≤ V)가
www.acmicpc.net
import heapq
import sys
INF = int(1e9)
def FastInput():
return sys.stdin.readline().rstrip()
node_num, vertex_num = map(int,FastInput().split())
starting_node=int(FastInput())
graph=[[] for _ in range(node_num+1)]
distance=[INF for _ in range(node_num+1)]
for i in range(vertex_num):
a,b,c=map(int,FastInput().split())
graph[a].append((b,c))
def Dijkstra(graph, starting_node, distance):
q=[]
heapq.heappush(q, (0, starting_node))
distance[starting_node]=0;
while q:
dist, now = heapq.heappop(q)
if distance[now] < dist:
continue
for i in graph[now]:
cost=dist+i[1]
if cost < distance[i[0]]:
distance[i[0]]=cost
heapq.heappush(q, (cost, i[0]))
Dijkstra(graph, starting_node, distance)
for i in range(1, node_num+1):
if distance[i]==INF:
print("INF")
else:
print(distance[i])
부등식에서 등호에 주의하자.
도시와 도시 사이에 간선이 여러개여도 알아서 최적경로를 찾아주니 걱정하지말자.
5. 플로이드 워셜
https://www.acmicpc.net/problem/11404
11404번: 플로이드
첫째 줄에 도시의 개수 n이 주어지고 둘째 줄에는 버스의 개수 m이 주어진다. 그리고 셋째 줄부터 m+2줄까지 다음과 같은 버스의 정보가 주어진다. 먼저 처음에는 그 버스의 출발 도시의 번호가
www.acmicpc.net
import sys
def FastInput():
return sys.stdin.readline().rstrip()
INF=int(1e9)
N=int(input())
M=int(input())
cost_table=[[INF for i in range(N+1)] for j in range(N+1)]
for m in range(M):
a,b,c=map(int,FastInput().split())
if cost_table[a][b]>c:
cost_table[a][b]=c
for i in range(1, N+1):
cost_table[i][i]=0
for pivot in range(1, N+1):
for node1 in range(1, N+1):
for node2 in range(1, N+1):
cost_table[node1][node2]=min(cost_table[node1][node2], cost_table[node1][pivot]+cost_table[pivot][node2])
for i in range(1,N+1):
for j in range(1,N+1):
if cost_table[i][j]==INF:
print("%d "%(0), end="")
else:
print("%d "%cost_table[i][j], end="")
print()
삼중 반복문으로 구현하는 플로이드 워셜 알고리즘이다.
삼중 반복문에서 pivot이 가장 바깥 반복문에 들어가야 함에 주의하자.
6. 서로소 집합
https://www.acmicpc.net/problem/1717
1717번: 집합의 표현
첫째 줄에 n(1 ≤ n ≤ 1,000,000), m(1 ≤ m ≤ 100,000)이 주어진다. m은 입력으로 주어지는 연산의 개수이다. 다음 m개의 줄에는 각각의 연산이 주어진다. 합집합은 0 a b의 형태로 입력이 주어진다. 이는
www.acmicpc.net
import sys
sys.setrecursionlimit(100000)
def Find(parent, x):
if parent[x] != x:
parent[x]= Find(parent, parent[x])
return parent[x]
def Union(parent, a, b):
a=Find(parent,a)
b=Find(parent,b)
if a<b:
parent[b]=a
else:
parent[a]=b
def FastInput():
return sys.stdin.readline().rstrip()
N, M=map(int, FastInput().split())
parent=list(range(N+1))
for i in range(M):
operation_type, a, b= map(int,FastInput().split())
if operation_type == 0:
Union(parent, a, b)
continue
a=Find(parent, a)
b=Find(parent, b)
if a == b:
print("YES")
else:
print("NO")
경로압축기법을 잘 기억하도록하고,
재귀제한을 더 크게 설정하는 것을 잊지 말자.
7. 크루스칼
https://www.acmicpc.net/problem/1922
1922번: 네트워크 연결
이 경우에 1-3, 2-3, 3-4, 4-5, 4-6을 연결하면 주어진 output이 나오게 된다.
www.acmicpc.net
import sys
sys.setrecursionlimit(1000000)
def FastInput():
return sys.stdin.readline().rstrip()
def Find(parent, x):
if parent[x] != x:
parent[x] = Find(parent, parent[x])
return parent[x]
def Union(parent, a, b):
a=Find(parent, a)
b=Find(parent, b)
if a<b:
parent[b]=a
else:
parent[a]=b
N=int(FastInput())
M=int(FastInput())
parent=list(range(N+1))
edges=[]
total_cost=0
for i in range(M):
a,b,c=map(int,FastInput().split())
edges.append((c,a,b))
edges.sort()
for e in edges:
cost, a, b= e
if Find(parent, a)!=Find(parent, b):
Union(parent, a, b)
total_cost+=cost
print(total_cost)
그리디 알고리즘과 서로소 집합 알고리즘을 활용하는 크루스칼 알고리즘 예제이다.
8. 위상정렬
https://www.acmicpc.net/problem/2252
2252번: 줄 세우기
첫째 줄에 N(1 ≤ N ≤ 32,000), M(1 ≤ M ≤ 100,000)이 주어진다. M은 키를 비교한 회수이다. 다음 M개의 줄에는 키를 비교한 두 학생의 번호 A, B가 주어진다. 이는 학생 A가 학생 B의 앞에 서야 한다는 의
www.acmicpc.net
from collections import deque
import sys
sys.setrecursionlimit(1000000)
def FastInput():
return sys.stdin.readline().rstrip()
N, M = map(int,FastInput().split())
indegree=[0]*(N+1)
graph=[[] for i in range(N+1)]
for i in range(M):
a, b = map(int, FastInput().split())
graph[a].append(b)
indegree[b]+=1
def TopologySort(graph, indegree):
result = []
q = deque()
for i in range(1, N+1):
if indegree[i]==0:
q.append(i)
while q:
now = q.popleft()
result.append(now)
for i in graph[now]:
indegree[i] -= 1
if indegree[i] == 0:
q.append(i)
for i in result:
print(i, end=' ')
TopologySort(graph, indegree)
'📁Algorithm & Codingtest > 알고리즘 공부' 카테고리의 다른 글
정렬된 리스트에 요소 추가하기 (0) | 2022.06.27 |
---|---|
알고리즘에 활용되는 파이썬 문법 (0) | 2022.03.27 |
알고리즘 학습 요약 (0) | 2021.12.05 |
댓글