[プログラマー]島(C++)への接続


コードテスト高得点Kit>欲張り
島の接続|問題のショートカット

回答(2022年02月26日SAT)💻)
🤔 プライベートトーク
ハイスコアキットには明確な分類があるため、これらの問題を解く際に、
もし私が分類タイプを知らずに問題に触れたら、どんな方法で問題に触れますか?
必ず考えます.
最初はdfsかbfsの問題ですか?と思っていたのですが、見ただけではカバーできない経路がいくつかあることがわかりました.
次のステップは、すべてのノードがアクセスされるまでアクセスチェックです.
アクセスしたことのないノードにのみブリッジを作成し,コードを作成した.
この場合、모든 섬이 통행 가능하도록を製造する必要があるという問題の条件を満たすことができない
この場合の反例テックは質問掲示板でも見つかる.
📌 cf) https://programmers.co.kr/questions/3981
解の核心
多少わけのわからない答えが、結局グーグルを通じて
MST(Minimum Spanning Tree)を利用して解決しなければならない問題であることに気づいた.
アルゴリズムの授業でMSTに通ったのを覚えています.
実際、これは私がコット問題でそれを運用したのは初めてです.
MSTはKruskal's AlgorithmまたはPrim's Algorithmを利用することができる
図と首都コードだけで学ぶアルゴリズムだからです.
実装を練習するために,コードを2つの方法で記述した.
11 Kruskal'sアルゴリズム参照
  • edge重み付け昇順
  • は、
  • を検査し、より小さなエッジからMSTに含まれるが、サイクルが形成されないことを保証する.
    👉 ループが形成されるか否かを決定するために、
    UnionFindアルゴリズムを使用してDisjoint Setsを表す
    私のブログにはUnionFindアルゴリズムに関する文章がないので、レポートを書きます.
    📌 cf) https://gmlwjd9405.github.io/2018/08/31/algorithm-union-find.html
    👉 edgeソートセクションでは、時間の複雑さを決定します.
    エッジソートを高速ソートなどの有効な方法で行うとします.
    O(ElogE)を持つ時間的複雑さ
    十一Prim's Algorithmを参照
  • 任意の開始ノード
  • を選択する.
  • このノードに隣接するエッジに接続するノードを選択する、MSTに含まれる
  • .
    すべてのノードが(n−1エッジ)を含むまで、上記の手順
  • MSTを繰り返します.
    👉 隣接ノードを巡回する操作は、すべてのノードの数を繰り返します.
    O(N^2)の時間的複雑さを持つ(ただし、最も少ないお尻を使用する場合、O(ElogN)に改善できる)
    高効率Tip
    エッジ数が少ない場合、Kruskal's AlgorithmはO(ElogE)複雑度を有する.
    edge数が多い場合にはO(n^2)の複雑さを持つPrim'sアルゴリズムが有効である
    この問題についてcosts의 길이(edge의 수)는 ((n-1)\*n)/2 이하の条件があったからです.
    要するに,Kruskal'sアルゴリズムで実現するのがより適切であると考えられる.
    🔽 Kruskal'sアルゴリズム使用コード(C++)
    #include <string>
    #include <vector>
    #include <algorithm>
    using namespace std;
    
    vector<int> parents;
    
    bool cmp(const vector<int> &a, vector<int> &b) {
        return a[2] < b[2];
    }
    
    int getParent(int x) {
        if (parents[x] == x) { return x; }
        return parents[x] = getParent(parents[x]);
    }
    
    void unionNodes(int x, int y) {
        x = getParent(x);
        y = getParent(y);
        if (x < y) { parents[y] = x; }
        else { parents[x] = y; }
    }
    
    // Solution #1 Kruskal's Algorithm 활용
    int solution(int n, vector<vector<int>> costs) {
        int answer = 0;
    
        // 부모 노드 담는 벡터 초기화
        for (int i=0; i<n; i++) { parents.push_back(i); }
        
        // 건설 비용이 적은 순으로 정렬
        sort(costs.begin(), costs.end(), cmp); 
    
        int size = costs.size();
        for (int i=0; i<size; i++) {
            int first = costs[i][0]; // 첫 번째 섬의 번호
            int second = costs[i][1]; // 두 번째 섬의 번호
            
            // 아직 통행이 불가능할 경우 (부모 노드가 다른 경우)
            if (getParent(first) != getParent(second)) {
                unionNodes(first, second); // 다리 건설
                answer += costs[i][2]; // 비용 추가
            }
        }
        
        return answer;
    }
    🔽 Prim'sアルゴリズム使用コード(C++)
    #include <string>
    #include <vector>
    #include <queue>
    using namespace std;
    
    struct Node {
        int id; // 섬의 번호
        int cost; // 비용
    };
    
    struct Cmp {
        bool operator()(const Node &a, const Node &b) {
            return a.cost > b.cost;
        }
    };
    
    vector<bool> visited(100, false);
    
    // Solution #2 Prim's Algorithm 활용
    int solution(int n, vector<vector<int>> costs) {
        int answer = 0;
    
        priority_queue<Node, vector<Node>, Cmp> minHeap; // 비용이 적은 순으로 정렬되는 최소힙
        minHeap.push({0, 0}); // 0번 섬을 기준으로 탐색 시작
        int size = costs.size();
        while (!minHeap.empty()) {
            Node curNode = minHeap.top();
            minHeap.pop();
    
            if (visited[curNode.id]) {
                // 이미 방문한 섬일 경우 스킵
                continue;
            }
    
            visited[curNode.id] = true;
            answer += curNode.cost;
    
            for (int i=0; i<size; i++) {
                // 인접한 섬들의 번호와 다리 건설 비용 minHeap에 push
                if (costs[i][0] == curNode.id) {
                    minHeap.push({costs[i][1], costs[i][2]});
                }
                else if (costs[i][1] == curNode.id) {
                    minHeap.push({costs[i][0], costs[i][2]});
                }
            }
        }
    
        return answer;
    }