最小支撐樹(Prim)算法

算法介紹

  • 學習記錄
  • 支撐樹
    • 覆蓋原圖的無環聯通子圖稱作原圖的一顆支撐樹(生成樹)
  • 最小支撐樹
    • 成本最低的支撐樹,而成本是各邊權重的總和
    • 頂點集V的任一非平凡子集和它的補集都構成一個割。
    • 如果邊uv滿足頂點u在子集,v在補集 則稱邊uv是割的跨越邊,也叫做橋。
  • prim算法
    • 算法原理
      • 最小支撐樹總是採用連接每一割的最短橋
    • 算法實現(貪心迭代)
      • 每一步迭代之前假設已經得到了最小支撐樹T的一顆子樹T(k) = (V(k), E(k)), 將V(k)和補集視作一個割,找到這個割的最短橋 e(k) = (v, u),然後擴展成更大的子樹 T(k+1) = (V(k+1), E(k+1));
      • 最初的T(1) 只包含單個頂點不包含邊,所以可以從圖中任意選擇

代碼實現

  • 借鑑了優先級算法
  • 每次T(k)擴充到T(k+1)的時候,可以將V(k)之外頂點u到V(k)的距離視作優先級,優先級更新函數就是更新新的鄰接頂點的優先級,將優先級替換成對應邊的權重
// 每次T(k)擴充到T(k+1)的時候,可以將V(k)之外頂點u到V(k)的距離視作優先級,優先級更新函數就是更新新的鄰接頂點的優先級,將優先級替換成對應的權重
// 每次挑選優先級數最小的那個頂點 所以挑選出來權重最小的邊
template <typename Tv, typename Te> struct PrimPu()
{
    virtual void operator() (Graph<Tv,Te> *graph, int v, int u){
        // 只針對v未發現的節點
        if (graph->status(u) != UNDISCOVER) {
            return;
        }

        // 更新父節點
        g->parent(u) = v;

        // 將當前頂點的優先級數更新成該邊的權重
        if (graph->weight(v, u) <  graph->priority(u)) {
            graph->priority(u) = graph->weight(v, u);
        }
    }

};



 // 優先級搜索算法
    template <typename PU> void pfs(int v, PU prioUpdater){
        // 重置圖狀態
        reset();

        // 時間標籤
        int clock = 0;
        int s = v;

        // 遍歷所有頂點
        do {
            // 所有未發現的頂點執行優先級搜索算法
            if (status(v) == UNDISCOVERED) {
                PFS(v, prioUpdater);
            }

            // 迭代到下一頂點
            v = ++v%n;
        } while (s != v);
    }

    // 連通域 優先級搜索框架
    template <typename PU> void PFS(int v, PU prioUpdater) {
        // 更新頂點優先級,狀態
        priority(v) = 0; // 最高優先級
        status(v) = VISITED;

        // 起點s加入遍歷樹中
        parent(s) = -1;

        // 遍歷所有頂點
        while(true) {
            // 更新當前頂點的鄰接頂點的優先級數和父級頂點
            for (int w = firstNbr(s); w > -1 ; w = nextNbr(s, w)) {
                prioUpdater(this,s, w);
            }

            // 獲取尚未加入遍歷樹中的所有頂點中優先級數最小的頂點
            int shortest = INT_MAX;
            for (int w =0; w < n ; w++) {
                if (status(w) == UNDISCOVERED && priority(w) < shortest) {
                    shortest = priority(w);
                    s = w;
                }
            }

            // TODO 自定義一些事情

            // 所有頂點都已經遍歷過了
            if (status(s) == VISITED) {
                break;
            }

            // 更新當前頂點的狀態
            status(s) = VISITED;
            type(parent(s), s) = TREE;
        }
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章