ํ์คํ ์น๐ ๊ฐ๋ฐ์ ์ง๋ง์ ๐ง๐ฝโ๐ป
โ ์ธ๊ณต์ง๋ฅ ๊ด์ฌ ๐ค
Categories
-
โฃ
โถ COMPUTER_SCIENCE
๐: 7 -
โฃ
โถ WEB
๐: 3 -
โฃ
โถ ETC
๐: 3-
โ
โฃ
ETCS
๐: 10 -
โ
โฃ
SUBBRAIN ๊ฐ๋ฐ๊ธฐ
๐: 5 -
โ
โ
YOS ๊ฐ๋ฐ๊ธฐ
๐: 1
-
โ
โฃ
-
โ
โถ AI
๐: 9-
โฃ
AITOOLS
๐: 3 -
โฃ
CV
๐: 2 -
โฃ
DEEP_LEARNING
๐: 1 -
โฃ
DATA_VIS
๐: 2 -
โฃ
GRAPH
๐: 1 -
โฃ
LIGHTWEIGHT
๐: 1 -
โฃ
MATH
๐: 1 -
โฃ
NLP
๐: 3 -
โ
STRUCTURED_DATA
๐: 2
-
โฃ
Python for Algorithms-Graph
- ๊ทธ๋ํ ์ํ
- ๊ทธ๋ํ ์ต๋จ ๊ฒฝ๋ก
- ์ต์ ์ ์ฅ ํธ๋ฆฌ(Minimum Spanning Tree)
- ์์ ์ ๋ ฌ(topological sort)
- ๋คํธ์ํฌ ํ๋ก์ฐ(Network flow)
Python for Algorithms-Graph
๋ ธ๋์ ๊ทธ๋ํ, ๊ฐ์ ์ ๋ํ ํ์๊ณผ ์๋ฃ๊ตฌ์กฐ
๊ทธ๋ํ ์ํ
BFS์ DFS ๋ ๋ค $O(n^2)$์ ์๊ฐ ๋ณต์ก๋๋ฅผ ๊ฐ์ง๋ค.
BFS(๋๋น ์ฐ์ ํ์)
def BFS(node_num, start, graph):
queue = deque([start]) # ์์ ์ ์ ํ์ ์ฝ์
visited = [False for node in range(node_num)]
while queue: # ํ๊ฐ ๋น๋ ๊น์ง
node = queue.popleft() # ํ์ ์ฒซ ๋ฒ์งธ ์์ ๋ฐํ
if not visited[node]: #
visited[node] = True # ๋ฐฉ๋ฌธ ํ์
do_something(node) # ์ํ๋ ์ฐ์ฐ ์ํ(ํ์, ๋ณ๊ฒฝ ๋ฑ)
for i, accessible in enumerate(graph[node]): # ๋ชจ๋ ๋
ธ๋ ์ค
if accessible and not visited[i]: # ์ฐ๊ฒฐ๋ฌ์ง๋ง ์์ง ๋ฐฉ๋ฌธํ์ง ์์ ๋
ธ๋์ ๋ํ์ฌ
visited[i] = True # ๋ฐฉ๋ฌธ ํ์
queue.append(i) # ํ์ ๋ฃ๊ธฐ
DFS(๊น์ด ์ฐ์ ํ์)
def DFS(node_num, start, graph):
stack = deque([start])
visited = [False for node in range(node_num)]
while stack:
node = stack.pop()
if not visited[node]:
visited[node] = True
do_something(node)
for i, accessible in enumerate(graph[node]):
if accessible and not visited[i]:
stack.append(i)
๊ทธ๋ํ ์ต๋จ ๊ฒฝ๋ก
๋ค์ต์คํธ๋ผ ์๊ณ ๋ฆฌ์ฆ
ํ ์ ์ ์์ ๋ค๋ฅธ ๋ชจ๋ ์ ์ ๊น์ง ๋น์ฉ์ ์ธก์ ํ๋ ์๊ณ ๋ฆฌ์ฆ
import heapq
INF = 987654321
class Edge(object):
def __init__(self, index, weight) -> None:
self.index = index
self.weight = weight
def __repr__(self) -> str:
return f"Node:{self.index} Weight:{self.weight}"
def __lt__(self, outer):
return self.weight < outer.weight
# D: ์ถ๋ฐ์ ์์ ๊ฐ ์ ์ ๊น์ง์ ์ต๋จ ๊ฒฝ๋ก ๊ฐ์ค์น ํฉ์ ์ ์ฅ
{: #d-์ถ๋ฐ์ ์์-๊ฐ-์ ์ ๊น์ง์-์ต๋จ-๊ฒฝ๋ก-๊ฐ์ค์น-ํฉ์-์ ์ฅ}
# P: ์ต๋จ ๊ฒฝ๋ก ํธ๋ฆฌ ์ ์ฅ
{: #p-์ต๋จ-๊ฒฝ๋ก-ํธ๋ฆฌ-์ ์ฅ}
def Dijkstra(G, r): # G: ๊ทธ๋ํ, r: ์์ ์ ์ , N: ๋
ธ๋์ ์
N = len(G)
D = [INF]*N # 1 ์์์ ๋ถํฐ ๊ฐ ๋
ธ๋๋ก ๊ฐ๋ฅ ์ต๋จ ๊ฑฐ๋ฆฌ๋ฅผ ๋ฌดํ๋๋ก ์ค์
P = [None]*N # 2 ์์์ง์ ๋ถํฐ ํด๋น์ง์ ๊น์ง์ ์ต๋จ ๊ฑฐ๋ฆฌ๋ฅผ ๊ตฌํ ์ ์๊ฒ ๋ ๋์์ฃผ๋ ๋ฐฐ์ด
visited = [False] * N # 3 ๋ฐฉ๋ฌธ ์ฌ๋ถ๋ฅผ ๋ชจ๋ False๋ก ์ค์
D[r] = 0 # 4 ์์ ์ง์ ๋ถํฐ ์์ ์ง์ ๊น์ง์ ๊ฑฐ๋ฆฌ 0์ผ๋ก ์ค์
min_heap = [Edge(r, 0)] # 5 ์์ ์ง์ ์ค์
while min_heap: # 6 ๋์ด์ ๊ฐฑ์ ํ ๋
ธ๋๊ฐ ์์๋ ๊น์ง ์คํ
# ์ต์ ๊ฑฐ๋ฆฌ ๋
ธ๋๋ก ์ค์
min_node = heapq.heappop(min_heap) # 7 ํ์ ํตํด ์๋ก ๊ฐฑ์ ๋ ์ต์ ๊ฑฐ๋ฆฌ ๋
ธ๋ ๊ฐ ๊ตฌํจ
visited[min_node.index] = True # 8 ์ด์ ์ต์๊ฑฐ๋ฆฌ๋ฅผ ๊ตฌํ ๊ฒ์ด๋ฏ๋ก visited ์ค์
for node in G[min_node.index]: # 9 ํด๋น ์ต์ ๊ฑฐ๋ฆฌ ๋
ธ๋์ ์ฐ๊ฒฐ๋ ๋
ธ๋๋ค์ ๋ํด
# 10 ํด๋น ๋
ธ๋์ ๊ธฐ์กด์ ์ต์ ๊ฑฐ๋ฆฌ๋ณด๋ค ๋ ๋ฎ์ ๋น์ฉ์ผ๋ก ๋๋ฌํ ์ ์๋ค๋ฉด
if not visited[node.index] and D[min_node.index] + node.weight < D[node.index]:
D[node.index] = D[min_node.index] + node.weight # 11 ์๋ก์ด ์ต์ ๊ฑฐ๋ฆฌ ๊ฐฑ์
heapq.heappush(min_heap, node) # 12 ๊ฐฑ์ ๋ ์ ๋ณด๋ฅผ ํตํด ๋ค๋ฅธ ๋
ธ๋๋ฅผ ๊ฐฑ์ ํ๊ธฐ ์ํด ํ์ ์ ์ฅ
# 13 node์ ๋ถ๋ชจ ๋
ธ๋(ํ๋ฒ์ ํํด ์ด๋ ๋
ธ๋๋ก๋ถํฐ ์ด ๋
ธ๋๋ก ์ค๋๊ฒ์ด ์ต๋จ๊ฒฝ๋ก์ธ๊ฐ?) ์ ์ฅ
P[node.index] = min_node.index
# P ์งํฉ์ ์ญ์์ ์์์ ์ ๊น์ง ๊ฐ๋ ๊ฒฝ๋ก๊ฐ ์์ ๋
ธ๋ -> ํด๋น ๋
ธ๋๋ก ๊ฐ๋ฅ ์ต๋จ ๊ฑฐ๋ฆฌ
return D, P # 14 ๋์ด์ ๊ฐฑ์ ํ ๊ฒ์ด ์๋ ๊ฒฝ์ฐ ๊ตฌํ ์ต์ ๊ฑฐ๋ฆฌ์ ์ต์ ๊ฑฐ๋ฆฌ ๊ฒฝ๋ก๋ฅผ ๋์ถ
import sys, heapq
INF = 9999999
nodeNum, edgeNum = map(int, input().split())
startNode = int(input())
edgeList = [[] for i in range(nodeNum+1)]
for i in range(edgeNum):
fr, to, wt = map(int, input().split())
edgeList[fr].append((wt, to))
distance = [INF for i in range(nodeNum+1)]
visited = [False for i in range(nodeNum+1)]
distance[startNode] = 0
hq = [(0,startNode)]
while(hq):
minweight, minIndex = heapq.heappop(hq)
visited[minIndex] = True
for weight, node in edgeList[minIndex]:
if not visited[node] and (distance[node] > (distance[minIndex] + weight)):
distance[node] = distance[minIndex] + weight
heapq.heappush(hq,(distance[node],node))
for i in range(1, len(distance)):
print(distance[i] if distance[i]!=INF else "INF")
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.PriorityQueue;
public class Main {
public static void main(String[] args) throws Exception {
BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
String[] input = bf.readLine().split(" ");
int V = Integer.parseInt(input[0]), E = Integer.parseInt(input[1]);
int start = Integer.parseInt(bf.readLine())-1;
ArrayList<int[]>[] edges = new ArrayList[V];
for (int i = 0; i < edges.length; i++) {
edges[i] = new ArrayList<int[]>();
}
for (int i = 0; i < E; i++) {
int[] inputs = Arrays.stream(bf.readLine().split(" ")).mapToInt(Integer::parseInt).toArray();
int fr = inputs[0]-1, to = inputs[1]-1, w = inputs[2];
edges[fr].add(new int[]{to, w});
}
int[] distance = new int[V];
Arrays.fill(distance, Integer.MAX_VALUE);
boolean[] visited = new boolean[V];
Arrays.fill(visited, false);
distance[start] = 0;
PriorityQueue<int[]> hq = new PriorityQueue<>(new Comparator<int[]>() {
public int compare(int[] s1, int[] s2) {
if (s1[1] > s2[1]){
return 1;
}
return -1;
}
});
hq.add(new int[]{start, 0});
while(hq.size() > 0){
int[] now = hq.remove();
visited[now[0]] = true;
for (int[] node : edges[now[0]]) {
if (!visited[node[0]] && distance[node[0]] > distance[now[0]] + node[1]){
distance[node[0]] = distance[now[0]] + node[1];
hq.add(new int[]{node[0],distance[node[0]]});
}
}
}
for (int dist : distance) {
System.out.println(dist != Integer.MAX_VALUE ? dist : "INF");
}
bf.close();
}
}
๋ฒจ๋ง ํฌ๋ ์๊ณ ๋ฆฌ์ฆ
์์ ๊ฐ์ค์น๊ฐ ์กด์ฌํ๋ ๊ฒฝ์ฐ์๋ ์ฌ์ฉํ ์ ์๋ ์ต๋จ ๊ฒฝ๋ก ์๊ณ ๋ฆฌ์ฆ
# ์ ์ ๊ฐฏ์, ์์ ์ ์ , ๊ฐ์ ์ ๋ณด
{: #์ ์ -๊ฐฏ์-์์-์ ์ -๊ฐ์ -์ ๋ณด}
def bellman_ford(node_num, start_node, edge_list):
INF = 99999999999
distance = [INF for _ in range(node_num)]
distance[start_node] = 0 # 1. ์์ ์ ์ ๋น์ฉ ์ด๊ธฐํ
for _ in range(node_num): # 2. ๊ฐ ์ ์ ์ ๋งํผ ๋น์ฉ์ ์
๋ฐ์ดํธ
for edge in edge_list:
from_node, to_node, weight = edge
# 3. ๋ง์ฝ ์์ ์ ์ ์์ ํด๋น ๊ฐ์ ์ ์์์ง์ ์ผ๋ก ๋ชป๊ฐ๋ฉด ๋ณด๋ฅ
if (distance[from_node] == INF):
continue
# 4. ๋ง์ฝ ๋ ์ ์ ๋น์ฉ์ ๊ฒฝ๋ก๊ฐ ์กด์ฌํ๋ฉด ๋น์ฉ ์
๋ฐ์ดํธ
if (distance[to_node] > distance[from_node] + weight):
distance[to_node] = distance[from_node] + weight
# 5. ํ๋ฒ ๋ ๋น์ฉ ์
๋ฐ์ดํธ๋ฅผ ์๋.
for edge in edge_list:
from_node, to_node, weight = edge
if (distance[from_node] == INF):
continue
# 6. ๊ฐ ์ ์ ์ ์๋งํผ ์
๋ฐ์ดํธ ํด๋ ์๋ก ๋น์ฉ์ด ์ค์ด๋ ๋ค๋ฉด ์์ ๊ฒฝ๋ก๊ฐ ์กด์ฌํ๋ค๋ ๋ป
if (distance[to_node] > distance[from_node] + weight):
return "Infinity loop caused by - weight."
# 7. ์๋ก ๋น์ฉ์ด ์ค์ง ์๋๋ค๋ฉด, ์์ ๊ฒฝ๋ก๊ฐ ์กด์ฌ ํ์ง ์๋๋ค.
return distance
ํ๋ก์ด๋ ์์ ์๊ณ ๋ฆฌ์ฆ
์์ ๊ฐ์ค์น๊ฐ ์กด์ฌํ๋ ๊ฒฝ์ฐ์ ๋ชจ๋ ์ ์ ๊ฐ์ ์ต๋จ ๊ฒฝ๋ก ๋น์ฉ์ ์ธก์ ํ๋ ์๊ณ ๋ฆฌ์ฆ
# graph: ๊ฐ์ ์ ๋ณด, ๊ฐ์ ์ด ์กด์ฌํ์ง ์๋ ๋
ธ๋ ๊ฐ์ ๋ฌดํ๋๋ก ์ด๊ธฐํ
{: #graph-๊ฐ์ -์ ๋ณด-๊ฐ์ ์ด-์กด์ฌํ์ง-์๋-๋
ธ๋-๊ฐ์-๋ฌดํ๋๋ก-์ด๊ธฐํ}
def floyd_warshall(graph):
# ๋ชจ๋ ์ ์ ๊ฐ์ ๊ฒฝ๋ก๋ฅผ ๊ตฌํ๋ฏ๋ก ๋ณดํต ์ ์ฌ ๋ฐฐ์ด ํํ์ ๊ฐ์ ์ ๋ณด๋ฅผ ์ฌ์ฉ
node_num = len(graph)
# ๋ชจ๋ ์ ์ ์ ์์, ๊ฒฝ์ , ๋์ฐฉ ์์์์ ๋ํด ๋น๊ต
for mid in range(node_num): # ๋ฐ๋์ ์ค๊ฐ ๊ฒฝ์ ์ ์ ๋ถํฐ ๋ฃจํ๋ฅผ ๋๋ ค์ผ ํ๋ค.
for start in range(node_num):
for end in range(node_num):
if (graph[start][end] > graph[start][mid] + graph[mid][end]):
graph[start][end] = graph[start][mid] + graph[mid][end]
return graph # ๋ชจ๋ ์ ์ ๊ฐ์ ์ต์ ๊ฒฝ๋ก ๋น์ฉ
์ต์ ์ ์ฅ ํธ๋ฆฌ(Minimum Spanning Tree)
๊ฐ์ค์น ๊ทธ๋ํ์์ ์ ์ฅ ํธ๋ฆฌ๋ฅผ ๊ตฌ์ฑํ๋ ๊ฐ์ ๋ค์ ๊ฐ์ค์น์ ํฉ์ด ์ต์์ธ ์ ์ฅ ํธ๋ฆฌ
ํ๋ฆผ ์๊ณ ๋ฆฌ์ฆ
ํ ์ ์ ์์ ์ฐ๊ฒฐ๋ ๊ฐ์ ๋ค ์ค ํ๋์ฉ ์ ํํ๋ฉด์ ์ต์ ์ ์ฅ ํธ๋ฆฌ๋ฅผ ๋ง๋ค์ด ๊ฐ๋ ๋ฐฉ์
import heapq
# G: ๊ทธ๋ํ, ์ธ๋ฑ์ค์์ ๊ฐ ์ ์๋ ์ ์ v์ ๋ํ ๊ฐ์ค์น val๋ค์ด ์กด์ฌ, s: ์์ ์ ์
{: #g-๊ทธ๋ํ-์ธ๋ฑ์ค์์-๊ฐ-์-์๋-์ ์ -v์-๋ํ-๊ฐ์ค์น-val๋ค์ด-์กด์ฌ-s-์์-์ ์ }
def MST_PRIM(G, s):
INF = 99999999
N = len(G)
key = [INF]*N # 1. ๊ฐ์ค์น๋ฅผ ๋ฌดํ๋๋ก ์ด๊ธฐํ
pi = [None]*N # 2. ํธ๋ฆฌ์์ ์ฐ๊ฒฐ๋ ๋ถ๋ชจ ์ ์ ์ด๊ธฐํ
visited = [False]*N # 3. ๋ฐฉ๋ฌธ ์ฌ๋ถ ์ด๊ธฐํ
key[s] = 0 # 4. ์์ ์ ์ ์ ๊ฐ์ค์น๋ฅผ 0์ผ๋ก ์ค์
minHeap = [(key[s], s)]
while minHeap: # 5. ํ์ด ๋น๋๊น์ง(=๋ ์ด์ ๊ฐฑ์ ํ ์ ์ ์ด ์์๋ ๊น์ง) ์คํ
_minWeight, minIndex = heapq.heappop(minHeap) # 6. ๊ฐฑ์ ํ ์ต์ ๊ฐ์ค์น ์ ์ ์ฐพ๊ธฐ
if not visited[minIndex]:
visited[minIndex] = True # 7. ์ต์ ๊ฐ์ค์น ์ ์ ๋ฐฉ๋ฌธ์ฒ๋ฆฌ
for v, val in G[minIndex]: # 8. ์ ํ ์ ์ ์ ์ธ์ ํ ์ ์ ๋ค์ ๋ํด
if not visited[v] and val < key[v]: # 9 ๋ฐฉ๋ฌธํ์ง ์์๊ณ ๊ฐฑ์ ๋ ์ ์๋ ์ ์ ์ด๋ฉด,
key[v] = val # 10. ๊ฐ์ค์น ๊ฐฑ์
pi[v] = minIndex # 11. ํธ๋ฆฌ์์ ์ฐ๊ฒฐ๋ ๋ถ๋ชจ ์ ์
# 12 ๊ฐฑ์ ๋ ์ ๋ณด๋ฅผ ์ฒ๋ฆฌํ๊ธฐ ์ํด ํ์ ์
๋ ฅ
heapq.heappush(minHeap, (key[v], v))
return key, pi # ๊ฐฑ์ ๋ ๊ฐ์ค์น์ ์ฐ๊ฒฐ ์ํ ์ถ๋ ฅ
ํฌ๋ฃจ์ค์ปฌ ์๊ณ ๋ฆฌ์ฆ
์ฌ์ดํด์ด ์๊ธฐ์ง ์๋๋ก ์ต์ ๊ฐ์ค์น ๊ฐ์ ์ ํ๋์ฉ ์ ํํด์ ์ต์ ์ ์ฅ ํธ๋ฆฌ๋ฅผ ์ฐพ๋ ์๊ณ ๋ฆฌ์ฆ
์ฌ์ดํด์
์ํธ ๋ฐฐํ ์งํฉ
์ ์ด์ฉํด ๊ฐ์งํ๋ค.
def MST_KRUSKA(G):
mst = [] # 1. ์ต์ ๊ฑฐ๋ฆฌ ๊ฐ์ ์งํฉ์ผ๋ก ๊ณต์งํฉ ์์ฑ
for i in range(N): # 2. ๊ฐ ๋
ธ๋๋ฅผ ์งํฉ์ผ๋ก ๋ง๋ค๊ธฐ
Make_Set(i)
G.sort(key = lambda t:t[2]) # 3. ๊ฐ์ค์น ๊ธฐ์ค์ผ๋ก ์ ๋ ฌ
mst_cost = 0 # 4. MST ๊ฐ์ค์น
while len(mst) < N-1: # 5. ํ์ํ ๊ฐ์ ์ ๊ฐฏ์(๋
ธ๋ ๊ฐฏ์ - 1)๋งํผ
u, v, val = G.pop(0) # 6. ์ต์ ๊ฐ์ค์น ๊ฐ์ ๊ฐ์ ธ์ค๊ธฐ
if Find_Set(u) != Find_Set(v): # 7 ๋ง์ฝ to node์ from node๊ฐ ๊ฐ์ ์งํฉ์ ์์ง ์๋ค๋ฉด
Union(u, v) # 8 ๋ ๋
ธ๋๋ฅผ ๊ฐ์ ์งํฉ์ผ๋ก ํฉ์น๊ธฐ
mst.append((u,v)) # 9 ์ต์ ๊ฑฐ๋ฆฌ ๊ฐ์ ์งํฉ์ (u, v) ์ถ๊ฐ
mst_cost += val
์์ ์ ๋ ฌ(topological sort)
์ ํฅ ๋น์ฌ์ดํด ๊ทธ๋ํ์์ ์ฌ์ฉ ๊ฐ๋ฅํ ์ฐจ์(degree)์ ๋ฐ๋ผ ์ ๋ ฌํ๋ ์๊ณ ๋ฆฌ์ฆ
๋ง์ฝ, ์๊ณ ๋ฆฌ์ฆ ์ข ๋ฃ๋ ๋ค, ์ ๋ ฌ์ ํฌํจ๋์ง ์์ ์ ์ ์ด ์๋ค๋ฉด, ์ฌ์ดํด์ด ์กด์ฌํ๋ค๋ ์๋ฏธ์ด๋ค.
# ๋ค์ด์ค๋ ์ฐจ์์ ๋๊ฐ๋ ์ฐจ์์ ๋ํ ์ ๋ณด๊ฐ ํ์
{: #๋ค์ด์ค๋-์ฐจ์์-๋๊ฐ๋-์ฐจ์์-๋ํ-์ ๋ณด๊ฐ-ํ์}
def topol_sort(indegree, outdegree):
node_num = len(indegree)
stack = []
sorted_node = []
for i in range(node_num):
if len(indegree[i]) == 0: # 1. ๋ค์ด์ค๋ ๊ฐ์ ์ด ์๋ ์ ์ ๋ถํฐ ์ฒ๋ฆฌ
stack.append(i)
while stack: # 2. ๋์ด์ ์ฒ๋ฆฌํ ์ ์ ์ด ์์ ๋ ๊น์ง
min_node = stack.pop() # 3. ์ฐจ์๊ฐ 0์ธ ์ ์ ํ๋ ๊บผ๋ด๊ธฐ
sorted_node.append(min_node) # 4. ์ ๋ ฌ ๋ฐฐ์ด์ ์
๋ ฅํ๊ณ ์ ์ ์ ์ ๊ฑฐ
for to_node in outdegree[min_node]: # 5. ์ ์ ์์ ๋๊ฐ๋ ๋ฐฉํฅ์ ์ ์ ๋ค์
indegree[to_node].remove(min_node) # 6. ๊ฐ์ ์ญ์
if len(indegree[to_node]) == 0: # 7. ๋ง์ฝ ๊ฐ์ ์ญ์ ๋ก ์ธํด ์ฐจ์๊ฐ 0์ด ๋๋ฉด
stack.append(stack, to_node) # 8. ๋ค์ ์ฒ๋ฆฌ๋ ์ ์ ์ผ๋ก ์คํ์ ์
๋ ฅ
return sorted_node # 9. ์ฐจ์ ๋ณ๋ก ์ ๋ ฌ๋ ๋ฐฐ์ด ๋์ถ
์คํ ๋์ ํ๋ฅผ ์ฌ์ฉํ ์ ์์ผ๋ฉฐ, ์ด ๊ฒฝ์ฐ ์ ๋ต์ธ ๋ค๋ฅธ ๊ฒฐ๊ณผ๊ฐ ๋์จ๋ค.
๋คํธ์ํฌ ํ๋ก์ฐ(Network flow)
Source ๋ ธ๋๋ถํฐ Sink ๋ ธ๋๊น์ง์ ๋ณด๋ผ ์ ์๋ ์ต๋ ์ ๋๊ณผ ๊ฒฝ๋ก๋ฅผ ๊ตฌํ๋๋ฐ ์ฌ์ฉํ๋ ์๊ณ ๋ฆฌ์ฆ
์๋๋ชฌ๋-์นดํ (Edmonds-Karp Algorithm, bfs)
ํ๋ฅผ ์ด์ฉํ BFS ๋์ ์คํ์ ์ด์ฉํ DFS๋ฅผ ์ด์ฉํ๋ฉด ํฌ๋-ํ์ปค์จ ์๊ณ ๋ฆฌ์ฆ์ด ๋์ง๋ง, ๋ณดํต ์๋๋ชฌ๋-์นดํ ์๊ณ ๋ฆฌ์ฆ ๋ณด๋ค ๋นํจ์จ์ ์ด๋ค.
from collections import deque
nodeCount, pipeCount = map(int, input().split())
edges = [[] for i in range(nodeCount)]
capacities = [[0 for i in range(nodeCount)] for j in range(nodeCount)]
flows = [[0 for i in range(nodeCount)] for j in range(nodeCount)]
for i in range(pipeCount):
fr, to, cap = map(int, input().split())
edges[fr].append(to)
edges[to].append(fr)
capacities[fr][to] += cap
source = 0
sink = 1
totalFlow = 0
while True:
p = [-1 for i in range(nodeCount)]
q = deque([source]) # ํ ๋์ ์คํ ์ฌ์ฉํ๋ฉด ํฌ๋-ํ์ปค์จ
p[source] = source
while q and p[sink] == -1:
now = q.popleft()
for to in range(nodeCount):
# ์ฐ๊ฒฐ๋์ง ์์๊ฑฐ๋, ์ด๋ฏธ ๊ฐ๋ ์ฌ์ฉ์ค์ด๊ฑฐ๋ ์ด๋ฏธ ๋ฐฉ๋ฌธํ๊ฑฐ๋, ์ฒ์์ผ๋ก ๋์๊ฐ๋ ๊ฒฝ์ฐ์๋ ์ ์ธ
if capacities[now][to] > 0 and capacities[now][to] > flows[now][to] and p[to] == -1 and to != source:
p[to] = now
q.append(to)
if (p[sink] != -1):
now = sink
minCap = 987654321
while now != source:
minCap = min(capacities[p[now]][now], minCap)
now = p[now]
now = sink
while now != source:
flows[p[now]][now] += minCap
flows[now][p[now]] -= minCap # ์ ๋์ ์์์ ์ฃผ์
now = p[now]
totalFlow += minCap
print(totalFlow)
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;
public class Main {
public static void main(String[] args) throws Exception {
BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(bf.readLine());
int pipeCount = Integer.parseInt(st.nextToken());
int nodeCount = Integer.parseInt(st.nextToken());
int source = Integer.parseInt(st.nextToken());
int sink = Integer.parseInt(st.nextToken());
int[][][] edges = new int[nodeCount][nodeCount][2]; //[from][to][cap,flow]
for (int i = 0; i < edges.length; i++) {
for (int j = 0; j < edges.length; j++) {
edges[i][j][0] = 0;
edges[i][j][1] = 0;
}
}
for (int i = 0; i < pipeCount; i++) {
StringTokenizer st2 = new StringTokenizer(bf.readLine());
int fr = Integer.parseInt(st2.nextToken());
int to = Integer.parseInt(st2.nextToken());
int w = Integer.parseInt(st2.nextToken());
edges[fr][to][0] += w; // ๊ฐ์ ๋
ธ๋ ๊ฐ์ ์ฌ๋ฌ ๊ฐ์ ์ด ์๋ ๊ฒฝ์ฐ๋ฅผ ์ํด ๋ง์
// edges[to][fr][0] += w;
// ๋ง์ฝ, ์๋ฐฉํฅ ๊ทธ๋ํ์ด๋ฉด ๋ฐ๋ ๋ฐฉํฅ์ผ๋ก๋ ์ถ๊ฐ
}
int max_flow = 0;
int[] pred = new int[nodeCount];
do {
for (int i = 0; i < pred.length; i++) {
pred[i] = -1;
}
pred = bfs(source, edges, pred);
if (pred[sink] != -1) {
int df = Integer.MAX_VALUE;
for (int i = sink; i != source; i = pred[i]) {
int cap = edges[pred[i]][i][0];
int flow = edges[pred[i]][i][1];
df = Math.min(df, cap - flow);
}
for (int i = sink; i != source; i = pred[i]) {
edges[pred[i]][i][1] += df;
edges[i][pred[i]][1] -= df;
}
max_flow += df;
}
} while (pred[sink] != -1);
System.out.println(max_flow);
bf.close();
}
private static int[] bfs(int source, int[][][] edges, int[] pred) {
Queue<Integer> q = new LinkedList<Integer>();
q.add(source);
while (q.size() > 0) {
int now = q.remove();
for (int i = 0; i < edges.length; i++) {
int to = i;
int cap = edges[now][i][0];
int flow = edges[now][i][1];
if (pred[to] == -1 && cap > 0 && cap > flow && to != source) {
pred[to] = now;
q.add(to);
}
}
}
return pred;
}
}
์ด๋ถ ๋งค์นญ(Bipartite Matching)
๋ ๊ทธ๋ฃน์ ๋
ธ๋๋ฅผ ์ผ๋์ผ ๋งค์นญ ์ํค๋ ๋ฐฉ๋ฒ์ ์ฌ์ฉ๋๋ ์๊ณ ๋ฆฌ์ฆ
๋จผ์ ํฌ๋-ํ์ปค์จ์ ์ด์ฉํ dfs ์๊ณ ๋ฆฌ์ฆ์ ์ด์ฉํ ์ ์๋ค.
title: ์ด๋ถ ๋งค์นญ ์๊ณ ๋ฆฌ์ฆ
ํ ๋ ธ๋๋ฅผ ์ง์ง์ -> ๋ค์ ๋ ธ๋๋ฅผ ์ง์ง์ ์, ์ด์ ๋ ธ๋์ ๊ฒน์น ๊ฒฝ์ฐ ์ด์ ๋ ธ๋๋ฅผ ๋ค๋ฅธ ์๊ณผ ์ง์ง์-> ๊ทธ๋ก ์ธํด ๋ ๋ค๋ฅธ ๋ ธ๋์ ๊ฒน์น ์, ๊ทธ ์ด์ ์ ์ด์ ๋ ธ๋๋ฅผ ๋ค๋ฅธ ์๊ณผ ์ง์ง์โฆ
- ๋ง์ฝ ์ด๋ฏธ ์๋ก ์ง์ง์ ๋ ธ๋์ ๋์ฐฉํ๋ฉด ํด๋น ๋ ธ๋๋ ์ง์ง์ ์ ์์
- ์๋ก์ด ์์ ๋ง๋ค์ด์ฃผ๋๋ฐ ์ฑ๊ณตํ๋ฉด ํด๋น ๋
ธ๋๋ ์ง์ง์ ์ ์์
~~~python
ACount, BCount = map(int, input().split())
edges = [list(map(int, input().split()))[1:] for _ in range(ACount)]
visited = [False for _ in range(ACount)]
A2B = [-1 for _ in range(ACount)]
B2A = [-1 for _ in range(BCount)] # prevent 0 == False
def dfs(a):
visited[a] = True # ์ผ๋จ ์์๋ก ์ง์ ์ง์ด์ค๋ค.
for b in edges[a]:
if B2A[b]==-1 or (not visited[B2A[b]] and dfs(B2A[b])): # ์ง์ด ์ง์ด์ง์ง ์์๊ฑฐ๋, ์ง ๋ฐ์ด๋ด๊ธฐ์ ์ฑ๊ณตํ ๊ฒฝ์ฐ
A2B[a], B2A[b] = b, a # ์๋ก ์ง์ง์ด์ฃผ๊ธฐ
return True
return False# ๋ชจ๋ ๋ฐ๋ ๋
ธ๋์ ๋ํด ์ง๋ฐ์ด๋ด๊ธฐ์ ์คํจํ๋ฉด ์ง ๋ถ๊ฐ
result = 0
for i in range(ACount): # ๊ฐ ๋
ธ๋์ ๋ํ์ฌ
if A2B[i]==-1: # ์์ง ํด๋น ๋
ธ๋๊ฐ ์ง์ง์ด์ง์ง ์์์ผ๋ฉด
visited = [False for _ in range(ACount)]
if dfs(i): result+=1 # ์ฑ๊ณต์ ์ง ์ฆ๊ฐ
print(result) # A2B, B2A : Mapping
<!-- @#@-example@#@์ด๋ถ ๋งค์นญ ์๊ณ ๋ฆฌ์ฆ@#@ -->
ํน์ ์์ ์๋๋ชฌ๋-์นดํ ์๊ณ ๋ฆฌ์ฆ์ ์ด์ฉํ ์ ์๋ค.
<!-- #@#callout-example#@#์๋๋ชฌ๋-์นดํ ์๊ณ ๋ฆฌ์ฆ์ ์ด์ฉํ ํด๊ฒฐ($O(|V||E|)$)#@#- -->
title: ์๋๋ชฌ๋-์นดํ ์๊ณ ๋ฆฌ์ฆ์ ์ด์ฉํ ํด๊ฒฐ($O(|V||E|)$)
~~~java
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;
public class Main {
public static void main(String[] args) throws Exception {
BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
String[] inputs = bf.readLine().split(" ");
int cowCount = Integer.parseInt(inputs[0]);
int roomCount = Integer.parseInt(inputs[1]);
int source = 0;
int sink = cowCount+roomCount+1;
int[][][] edges = new int[cowCount+roomCount+2][cowCount+roomCount+2][2];
for (int[][] cow : edges) {
for (int[] edge : cow) {
edge[0] = 0;
edge[1] = 0;
}
}
// ์ธ์์ ์ธ ์์ค์ ์ฑํฌ ๋
ธ๋ ๋ง๋ค์ด์ฃผ๊ธฐ
for (int i = 1; i <= cowCount; i++) {
edges[source][i][0] = 1;
}
for (int i = cowCount + 1; i < cowCount+roomCount+1; i++} {
edges[i][sink][0] = 1;
}
for (int cow = 1; cow <= cowCount; cow++) {
int[] cowInfo = Arrays.stream((bf.readLine().split(" "))).mapToInt(Integer::parseInt).toArray();
int rooms = cowInfo[0];
for (int j = 1; j <= rooms; j++) {
int room = cowInfo[j] + cowCount;
edges[cow][room][0] = 1;
edges[cow][room][1] = 0;
}
}
int max_flow = 0;
int[] pred = new int[cowCount+roomCount+2];
do {
for (int i = 0; i < pred.length; i++) {
pred[i] = -1;
}
pred = bfs(pred,edges);
if (pred[sink] != -1){
for (int i = sink; pred[i] != -1; i = pred[i]) {
edges[pred[i]][i][1] += 1;
edges[i][pred[i]][1] -= 1;
}
max_flow += 1;
}
} while (pred[sink] != -1);
System.out.println(max_flow);
bf.close();
}
private static int[] bfs(int[] pred, int[][][] edges) {
Queue<Integer> q = new LinkedList<Integer>();
q.add(0);
while(q.size() > 0){
int now = q.remove();
for (int i = 0; i < edges[now].length; i++) {
int cap = edges[now][i][0];
int flow = edges[now][i][1];
if (pred[i] == -1 && i != 0 && cap-flow > 0){
pred[i] = now;
q.add(i);
}
}
}
return pred;
}
}
_articles/computer_science/algorithm/Python for Algorithms-Graph.md