ํ’€์Šคํƒ ์›น๐ŸŒ ๊ฐœ๋ฐœ์ž ์ง€๋ง์ƒ ๐Ÿง‘๐Ÿฝโ€๐Ÿ’ป
โž• ์ธ๊ณต์ง€๋Šฅ ๊ด€์‹ฌ ๐Ÿค–


Categories


Recent views

  • 1
  • 2
  • 3
  • 4
  • 5

Python for Algorithms-Graph

Python for Algorithms-Graph

๋…ธ๋“œ์™€ ๊ทธ๋ž˜ํ”„, ๊ฐ„์„ ์— ๋Œ€ํ•œ ํƒ์ƒ‰๊ณผ ์ž๋ฃŒ๊ตฌ์กฐ

๊ทธ๋ž˜ํ”„ ์ˆœํšŒ

BFS์™€ DFS ๋‘˜ ๋‹ค $O(n^2)$์˜ ์‹œ๊ฐ„ ๋ณต์žก๋„๋ฅผ ๊ฐ€์ง„๋‹ค.

BFS(๋„ˆ๋น„ ์šฐ์„  ํƒ์ƒ‰)

๐Ÿงพ๏ธ 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(๊นŠ์ด ์šฐ์„  ํƒ์ƒ‰)

๐Ÿงพ๏ธ 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)

๊ทธ๋ž˜ํ”„ ์ตœ๋‹จ ๊ฒฝ๋กœ

๋‹ค์ต์ŠคํŠธ๋ผ ์•Œ๊ณ ๋ฆฌ์ฆ˜

ํ•œ ์ •์ ์—์„œ ๋‹ค๋ฅธ ๋ชจ๋“  ์ •์ ๊นŒ์ง€ ๋น„์šฉ์„ ์ธก์ •ํ•˜๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜

๐Ÿ’ก ์กฐ๊ธˆ ๋ณ€ํ˜•ํ•˜์—ฌ ์ตœ๋‹จ ๊ฒฝ๋กœ ๋˜ํ•œ ์•Œ ์ˆ˜ ์žˆ๋‹ค.(์•„๋ž˜ ์ฝ”๋“œ ์ฐธ์กฐ)
๐Ÿงพ๏ธ ๋‹ค์ต์ŠคํŠธ๋ผ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์˜ˆ์‹œ $O(NlogM + M)$
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();
    }
}

๋ฒจ๋งŒ ํฌ๋“œ ์•Œ๊ณ ๋ฆฌ์ฆ˜

์Œ์˜ ๊ฐ€์ค‘์น˜๊ฐ€ ์กด์žฌํ•˜๋Š” ๊ฒฝ์šฐ์—๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ตœ๋‹จ ๊ฒฝ๋กœ ์•Œ๊ณ ๋ฆฌ์ฆ˜

๐Ÿงพ๏ธ ๋ฒจ๋งŒ ํฌ๋“œ ์•Œ๊ณ ๋ฆฌ์ฆ˜ $O(n^2)$ ์˜ˆ์‹œ
# ์ •์  ๊ฐฏ์ˆ˜, ์‹œ์ž‘ ์ •์ , ๊ฐ„์„  ์ •๋ณด
{: #์ •์ -๊ฐฏ์ˆ˜-์‹œ์ž‘-์ •์ -๊ฐ„์„ -์ •๋ณด}
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

ํ”Œ๋กœ์ด๋“œ ์›Œ์…œ ์•Œ๊ณ ๋ฆฌ์ฆ˜

์Œ์˜ ๊ฐ€์ค‘์น˜๊ฐ€ ์กด์žฌํ•˜๋Š” ๊ฒฝ์šฐ์— ๋ชจ๋“  ์ •์  ๊ฐ„์˜ ์ตœ๋‹จ ๊ฒฝ๋กœ ๋น„์šฉ์„ ์ธก์ •ํ•˜๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜

๐Ÿงพ๏ธ ํ”Œ๋กœ์ด๋“œ ์›Œ์…œ ์•Œ๊ณ ๋ฆฌ์ฆ˜ $O(n^3)$ ์˜ˆ์‹œ
# 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)

๊ฐ€์ค‘์น˜ ๊ทธ๋ž˜ํ”„์—์„œ ์‹ ์žฅ ํŠธ๋ฆฌ๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ๊ฐ„์„ ๋“ค์˜ ๊ฐ€์ค‘์น˜์˜ ํ•ฉ์ด ์ตœ์†Œ์ธ ์‹ ์žฅ ํŠธ๋ฆฌ

ํ”„๋ฆผ ์•Œ๊ณ ๋ฆฌ์ฆ˜

ํ•œ ์ •์ ์—์„œ ์—ฐ๊ฒฐ๋œ ๊ฐ„์„ ๋“ค ์ค‘ ํ•˜๋‚˜์”ฉ ์„ ํƒํ•˜๋ฉด์„œ ์ตœ์†Œ ์‹ ์žฅ ํŠธ๋ฆฌ๋ฅผ ๋งŒ๋“ค์–ด ๊ฐ€๋Š” ๋ฐฉ์‹

๐Ÿงพ๏ธ ํ”„๋ฆผ ์•Œ๊ณ ๋ฆฌ์ฆ˜ $O(n\log n)$ ์˜ˆ์‹œ
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)์— ๋”ฐ๋ผ ์ •๋ ฌํ•˜๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜

โž• ์ฐจ์ˆ˜(degree)๋ž€, ํ•ด๋‹น ์ •์ ์— ์—ฐ๊ฒฐ๋œ ๊ฐ„์„ ์˜ ์ˆ˜๋ฅผ ์˜๋ฏธํ•˜๋ฉฐ, ๋“ค์–ด์˜ค๋Š” Indegree์™€ ๋‚˜๊ฐ€๋Š” Outdegree๋กœ ๋‚˜๋‰œ๋‹ค.

๋งŒ์•ฝ, ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์ข…๋ฃŒ๋œ ๋’ค, ์ •๋ ฌ์— ํฌํ•จ๋˜์ง€ ์•Š์€ ์ •์ ์ด ์žˆ๋‹ค๋ฉด, ์‚ฌ์ดํด์ด ์กด์žฌํ•œ๋‹ค๋Š” ์˜๋ฏธ์ด๋‹ค.

๐Ÿงพ๏ธ ์œ„์ƒ ์ •๋ ฌ $O(N)$ ์˜ˆ์‹œ
# ๋“ค์–ด์˜ค๋Š” ์ฐจ์ˆ˜์™€ ๋‚˜๊ฐ€๋Š” ์ฐจ์ˆ˜์— ๋Œ€ํ•œ ์ •๋ณด๊ฐ€ ํ•„์š”
{: #๋“ค์–ด์˜ค๋Š”-์ฐจ์ˆ˜์™€-๋‚˜๊ฐ€๋Š”-์ฐจ์ˆ˜์—-๋Œ€ํ•œ-์ •๋ณด๊ฐ€-ํ•„์š”}
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;
    }
}