[コンセプト]10.グラフィック理論

23960 ワード

リンクテキスト

集合データ構造

  • データ構造
  • まで、集合資料構造は2つの演算をサポートしませんでした.
  • とセット(Union):2つの要素を含むセットを1つのセットに統合する演算
  • 検索
  • (Find):エレメントが属する集合が何であるかを示す演算
    集合データ構造は、連合検索データ構造
  • と呼ばれる.
  • の複数の連結演算が与えられると、集合資料構造の動作過程は以下の通りである:
  • の集合演算を確認し、2つの相互接続ノードA,Bを確認する
    a.AとBのルートノードA’,B’をそれぞれ探す
    b.A′をB′に設定親ノード
  • プロセス
  • は、すべての並列セット(Union)演算が処理されるまで繰り返される.

    集約リソース構造:基本的な実装方法(Python)

    # 특정 원소가 속한 집합을 찾기
    def find_parent(parent, x):
        # 루트 노드가 아니라면, 루트 노드를 찾을 때까지 재귀적으로 호출
        if parent[x] != x:
            return find_parent(parent, parent[x])
        return x
    
    # 두 원소가 속한 집합을 합치기
    def union_parent(parent, a, b):
        a = find_parent(parent, a)
        b = find_parent(parent, b)
        if a < b:
            parent[b] = a
        else:
            parent[a] = b
    
    # 노드의 개수와 간선(Union 연산)의 개수 입력 받기
    v, e = map(int, input().split())
    parent = [0] * (v + 1) # 부모 테이블 초기화하기
    
    # 부모 테이블상에서, 부모를 자기 자신으로 초기화
    for i in range(1, v + 1):
        parent[i] = i
    
    # Union 연산을 각각 수행
    for i in range(e):
        a, b = map(int, input().split())
        union_parent(parent, a, b)
    
    # 각 원소가 속한 집합 출력하기
    print('각 원소가 속한 집합: ', end='')
    for i in range(1, v + 1):
        print(find_parent(parent, i), end=' ')
    
    print()
    
    # 부모 테이블 내용 출력하기
    print('부모 테이블: ', end='')
    for i in range(1, v + 1):
        print(parent[i], end=' ')

    集合データ構造のみ集合データこうぞう:パス圧縮パスあっしゅく


    パス圧縮最適化
  • を使用して関数を検索できます.
  • ルックアップ(Find)関数を再呼び出し、親テーブル値
  • をすぐに更新します.
    # 특정한 원소가 속한 집합을 찾기
    def find_parent(parent, x):
        # 루트 노드가 아니라면, 루트 노드를 찾을 때까지 재귀적으로 호출
        if parent[x] != x:
            parent[x] = find_parent(parent, parent[x])
        return parent[x]
  • パス圧縮技術を用いて、各ノードに対してルックアップ(Find)関数を呼び出すと、そのノードのルートノードは親ノード
  • となる.
    同じ例
  • に対してすべてのUnion関数を処理し、各要素に対してFind関数を実行すると、親テーブルは更新されます:
  • 基本法と比較して,時間的複雑度は
  • 向上した.

    腎臓の木

  • 図にはすべてのノードが含まれており、ループが存在しないことを示す部分図
  • を含むすべてのノードは、互いに接続するループが存在しない条件もツリーの条件
  • である.

    さいしょうのびじゅ

  • 最もコストの低い拡張ツリーを探す必要がある場合はどうすればいいですか?
  • 例えば
  • は、N都市が存在すると仮定し、2つの都市の間に道路を設け、都市全体を相互に接続する
  • の2都市A,Bが選択すると、A~Bの経路が存在することを確保するために、道路
  • が設けられる.

    クルーズアルゴリズム

  • の代表的な最小伸長ツリーアルゴリズム
  • 階調アルゴリズム
  • に分類する
  • 具体的な動作過程は以下の通りである:
  • 1)幹線データを料金の昇順に並べる
    2)幹線を1本ずつ点検し、現在の幹線に周期が発生しているか確認する
  • サイクルが発生しない場合、最小伸長ツリーに含まれる
  • .
  • サイクルが発生する場合、最小伸長ツリーに含まれない
  • .
    3)すべての幹線に対して2回の過程を繰り返す

    クルーズアルゴリズム性能分析

  • クルースカルアルゴリズムは、幹線数がEの場合、O(logE)の時間的複雑度
  • を有する.
  • クルースカアルゴリズムで最も要求時間が多いのは、幹線ソートを実行する部分
  • である.
  • 標準ライブラリの使用𝐸データの並べ替えの時間的複雑度はO(ElogE)
  • である.

    クルーズアルゴリズム(Python)

    # 특정 원소가 속한 집합을 찾기
    def find_parent(parent, x):
        # 루트 노드가 아니라면, 루트 노드를 찾을 때까지 재귀적으로 호출
        if parent[x] != x:
            parent[x] = find_parent(parent, parent[x])
        return parent[x]
    
    # 두 원소가 속한 집합을 합치기
    def union_parent(parent, a, b):
        a = find_parent(parent, a)
        b = find_parent(parent, b)
        if a < b:
            parent[b] = a
        else:
            parent[a] = b
    
    # 노드의 개수와 간선(Union 연산)의 개수 입력 받기
    v, e = map(int, input().split())
    parent = [0] * (v + 1) # 부모 테이블 초기화하기
    
    # 모든 간선을 담을 리스트와, 최종 비용을 담을 변수
    edges = []
    result = 0
    
    # 부모 테이블상에서, 부모를 자기 자신으로 초기화
    for i in range(1, v + 1):
        parent[i] = i
    
    # 모든 간선에 대한 정보를 입력 받기
    for _ in range(e):
        a, b, cost = map(int, input().split())
        # 비용순으로 정렬하기 위해서 튜플의 첫 번째 원소를 비용으로 설정
        edges.append((cost, a, b))
    
    # 간선을 비용순으로 정렬
    edges.sort()
    
    # 간선을 하나씩 확인하며
    for edge in edges:
        cost, a, b = edge
        # 사이클이 발생하지 않는 경우에만 집합에 포함
        if find_parent(parent, a) != find_parent(parent, b):
            union_parent(parent, a, b)
            result += cost
    
    print(result)

    位相位置合わせ

  • サイクルのない方向図のすべてのノードを順番にリストして、方向性に違反しないようにします.
    例)選手科目の学習順序
  • を設定する.
    以上の3つの授業の適当な学習順序は?
    データ構造→アルゴリズム→高度アルゴリズム(O)
    データ構造→高度アルゴリズム→アルゴリズム(X)

    フェーズアライメントアルゴリズム


    キューの位相整列アルゴリズムを使用する動作手順は、次のとおりです.
    1)アクセス数0のすべてのノードをキューに入れる
    2)Q要求まで次の手順を繰り返す
  • a)キューから要素を取り出し、ノード上の幹線をグラフから
  • 削除する.
  • b)新たな入力差が0のノードをキュー
  • に入れる.
    =>結果は、各ノードがキューに入る順序が位相ソートを実行した結果と同じです.

    位相整列フィーチャー

  • 位相較正はDAGのみ
  • 直結ループパターン:非ループ方向図
  • 位相キャリブレーションでは、複数の答えが存在する可能性がある
  • フェーズでは、キューに2つ以上の新しい要素がある場合、複数の答えが存在します.
  • すべての要素にアクセスする前に、キューが空の場合、ループがあると判断できます.
  • サイクルに含まれる要素のうち、どの要素もキュー
  • に入ることができない.
  • スタックを有するDFSを用いて位相整合を行うこともできる

    フェーズアライメントアルゴリズムのパフォーマンス分析

  • 位相をソートするには、すべてのノードを順次チェックし、各ノードの配線を順次削除する必要がある.
  • 位相並べ替えアルゴリズムの時間的複雑度はO(V+E)
  • である.
    from collections import deque
    
    # 노드의 개수와 간선의 개수를 입력 받기
    v, e = map(int, input().split())
    # 모든 노드에 대한 진입차수는 0으로 초기화
    indegree = [0] * (v + 1)
    # 각 노드에 연결된 간선 정보를 담기 위한 연결 리스트 초기화
    graph = [[] for i in range(v + 1)]
    
    # 방향 그래프의 모든 간선 정보를 입력 받기
    for _ in range(e):
        a, b = map(int, input().split())
        graph[a].append(b) # 정점 A에서 B로 이동 가능
        # 진입 차수를 1 증가
        indegree[b] += 1
    
    # 위상 정렬 함수
    def topology_sort():
        result = [] # 알고리즘 수행 결과를 담을 리스트
        q = deque() # 큐 기능을 위한 deque 라이브러리 사용
    
        # 처음 시작할 때는 진입차수가 0인 노드를 큐에 삽입
        for i in range(1, v + 1):
            if indegree[i] == 0:
                q.append(i)
    
        # 큐가 빌 때까지 반복
        while q:
            # 큐에서 원소 꺼내기
            now = q.popleft()
            result.append(now)
            # 해당 원소와 연결된 노드들의 진입차수에서 1 빼기
            for i in graph[now]:
                indegree[i] -= 1
                # 새롭게 진입차수가 0이 되는 노드를 큐에 삽입
                if indegree[i] == 0:
                    q.append(i)
    
        # 위상 정렬을 수행한 결과 출력
        for i in result:
            print(i, end=' ')
    
    topology_sort()