S6-算法-普利姆算法【2021-02-08】

總目錄:地址如下看總綱

http://www.reibang.com/p/929ca9e209e8

1、應(yīng)用場景-修路問題

(1)有勝利鄉(xiāng)有7個村莊(A, B, C, D, E, F, G) ,現(xiàn)在需要修路把7個村莊連通
(2)各個村莊的距離用邊線表示(權(quán)) 氓英,比如 A – B 距離 5公里
(3)問:如何修路保證各個村莊都能連通镊折,并且總的修建公路總里程最短?
常規(guī)思路: 將10條邊,連接即可秋秤,但是總的里程數(shù)不是最小
正確思路:盡可能的選擇少的路線宏粤,并且每條路線最小,保證總里程數(shù)最少


image.png

2灼卢、最小生成樹

修路問題本質(zhì)就是就是最小生成樹問題绍哎, 最小生成樹(Minimum Cost Spanning Tree),簡稱MST

(1)給定一個帶權(quán)的無向連通圖,如何選取一棵生成樹,使樹上所有邊上權(quán)的總和為最小,這叫最小生成樹
(2)N個頂點芥玉,一定有N-1條邊
(3)包含全部頂點
(4)N-1條邊都在圖中
(5)求最小生成樹的算法主要是普里姆?算法和克魯斯卡爾算法


image.png

3蛇摸、普利姆算法

(1)普利姆(Prim)算法求最小生成樹,也就是在包含n個頂點的連通圖中灿巧,找出只有(n-1)條邊包含所有n個頂點的連通子圖赶袄,也就是所謂的極小連通子圖

(2)文字思路:看不懂也無所謂,概述而已抠藕,詳細(xì)看圖解
①設(shè)G=(V,E)是連通網(wǎng)饿肺,T=(U,D)是最小生成樹,V,U是頂點集合盾似,E,D是邊的集合
②若從頂點u開始構(gòu)造最小生成樹敬辣,則從集合V中取出頂點u放入集合U中,標(biāo)記頂點v的visited[u]=1(既被訪問過了)
③若集合U中頂點ui與集合V-U中的頂點vj之間存在邊零院,則尋找這些邊中權(quán)值最小的邊溉跃,但不能構(gòu)成回路,將頂點vj加入集合U中告抄,將邊(ui,vj)加入集合D中撰茎,標(biāo)記visited[vj]=1
④重復(fù)步驟②,直到U與V相等打洼,即所有頂點都被標(biāo)記為訪問過龄糊,此時D中有n-1條邊

(3)圖解思路:清晰一些逆粹,關(guān)于理解


image.png

4、代碼

public class PrimAlgorithm {
    public static void main(String[] args) {
        // 測試圖創(chuàng)建
        char[] data = new char[]{'A', 'B', 'C', 'D', 'E', 'F', 'G'};
        int verxs = data.length;
        //鄰接矩陣的關(guān)系使用二維數(shù)組表示,10000這個大數(shù)炫惩,表示兩個點不聯(lián)通
        int[][] weight = new int[][]{
                {10000, 5, 7, 10000, 10000, 10000, 2},
                {5, 10000, 10000, 9, 10000, 10000, 3},
                {7, 10000, 10000, 10000, 8, 10000, 10000},
                {10000, 9, 10000, 10000, 10000, 4, 10000},
                {10000, 10000, 8, 10000, 10000, 5, 4},
                {10000, 10000, 10000, 4, 5, 10000, 6},
                {2, 3, 10000, 10000, 4, 6, 10000},};

        //創(chuàng)建MGraph對象
        MGraph graph = new MGraph (verxs);
        //創(chuàng)建一個MinTree對象
        MinTree minTree = new MinTree ( );
        minTree.createGraph (graph, verxs, data, weight);
        //輸出
        minTree.showGraph (graph);
        //測試普利姆算法
        minTree.prim (graph, 0);
    }


}


// 構(gòu)建最小生成樹對象 --- 村莊圖
class MinTree {

    /**
     * 構(gòu)建圖的鄰接矩陣(初始化)
     *
     * @param graph  圖對象
     * @param verxs  圖對應(yīng)的頂點個數(shù)
     * @param data   圖的各個頂點編號僻弹,這里不是權(quán)值(編號作為表示,不用于計算他嚷;權(quán)值通常用于計算蹋绽,個人理解--阿K)
     * @param weight 圖的鄰接矩陣
     */
    public void createGraph(MGraph graph, int verxs, char[] data, int[][] weight) {

        for (int i = 0; i < verxs; i++) {// 遍歷各個頂點
            graph.data[i] = data[i];
            for (int j = 0; j < verxs; j++) {
                graph.weight[i][j] = weight[i][j];
            }
        }
    }

    // 顯示圖的鄰接矩陣
    public void showGraph(MGraph graph) {
        for (int[] link : graph.weight) {
            System.out.println (Arrays.toString (link));
        }
    }

    /**
     * @param graph 圖
     * @param v     表示從圖的第幾個頂點開始生成 'A'-0,'B'-1 ...
     */
    public void prim(MGraph graph, int v) {
        // visited[] 標(biāo)記節(jié)點(頂點)是否被訪問過
        int[] visited = new int[graph.verxs];

        // 初始化,默認(rèn) 0 是未訪問過爸舒,可以不寫蟋字,但是我愿意!
        for (int i = 0; i < visited.length; i++) {
            visited[i] = 0;
        }

        // 把當(dāng)前節(jié)點標(biāo)記為已訪問過
        visited[v] = 1;
        // h1 and h2 record double node of subscript(鄰接矩陣是二位數(shù)組扭勉,對應(yīng)著 double subscript)
        int h1 = -1;
        int h2 = -1;
        // 將 minWeight 初始化成大數(shù) 10000鹊奖,后面遍歷過程中會被替換(為什么初始化成大數(shù),因為這樣默認(rèn)是走不通的 根據(jù)案例設(shè)計)
        int minWeight = 10000;// 邊(最小權(quán)值)

        // 核心部分:
        for (int k = 1; k < graph.verxs; k++) {// 公式中 頂點個數(shù)為n 涂炎,邊為 n-1忠聚,所以 從 1開始

            // 該雙層循環(huán)作用:用于確定每一次生成的子圖,和哪個節(jié)點的距離最近
            // 子圖:就是圖解上的步驟 1 - 6 中唱捣, 1 是 A-C [7]两蟀, A-G[2] ,A-B[5] 震缭, 2 是 A-C[7] 赂毯,A-B[5] , G-B[3] 拣宰,G-E[4] 党涕,G-F[6] ......
            // 其實就是對圖遍歷兩遍,一遍訪問過的巡社,一遍沒訪問過的膛堤,有訪問過的根據(jù)沒訪問過的計算權(quán)值(邊),得出最小晌该,然后標(biāo)記為已經(jīng)訪問過肥荔,繼續(xù)循環(huán) k 層
            for (int i = 0; i < graph.verxs; i++) {// i 索引對應(yīng)的節(jié)點表示 被訪問過的節(jié)點,標(biāo)識為 0
                for (int j = 0; j < graph.verxs; j++) {// j 索引對應(yīng)的節(jié)點表示 未被訪問過的節(jié)點朝群,標(biāo)識為 1
                    if (visited[i] == 1 && visited[j] == 0 && graph.weight[i][j] < minWeight) {// 當(dāng)前節(jié)點的權(quán)值(邊)小于最小節(jié)點的權(quán)值(邊)
                        // 替換 minWeight(尋找已經(jīng)訪問過的結(jié)點和未訪問過的結(jié)點間的權(quán)值最小的邊)
                        minWeight = graph.weight[i][j];
                        h1 = i;
                        h2 = j;
                    }
                }
            }
            // 找到了一條邊燕耿,是最小的
            System.out.println ("邊<" + graph.data[h1] + "," + graph.data[h2] + "> 權(quán)值:" + minWeight);
            // 將當(dāng)前節(jié)點標(biāo)記為已經(jīng)訪問
            visited[h2] = 1;// 為什么 h1 不用置為已經(jīng)標(biāo)記? 因為h1 本身已經(jīng)是標(biāo)記好的用來篩選姜胖,所以沒必要
            // 重新設(shè)置為最大值
            minWeight = 10000;
        }
    }
}


// 圖對象
class MGraph {
    int verxs;     // 表示圖中節(jié)點的個數(shù)
    char[] data;   // 存放節(jié)點的數(shù)據(jù)
    int[][] weight;// 存放邊(既 鄰接矩陣)

    public MGraph(int verxs) {
        this.verxs = verxs;
        data = new char[verxs];
        weight = new int[verxs][verxs];
    }
}

5缸棵、倉庫坐標(biāo)

image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子堵第,更是在濱河造成了極大的恐慌,老刑警劉巖隧出,帶你破解...
    沈念sama閱讀 219,366評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件踏志,死亡現(xiàn)場離奇詭異,居然都是意外死亡胀瞪,警方通過查閱死者的電腦和手機针余,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來凄诞,“玉大人圆雁,你說我怎么就攤上這事》” “怎么了伪朽?”我有些...
    開封第一講書人閱讀 165,689評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長汛蝙。 經(jīng)常有香客問我烈涮,道長,這世上最難降的妖魔是什么窖剑? 我笑而不...
    開封第一講書人閱讀 58,925評論 1 295
  • 正文 為了忘掉前任坚洽,我火速辦了婚禮,結(jié)果婚禮上西土,老公的妹妹穿的比我還像新娘讶舰。我一直安慰自己,他們只是感情好需了,可當(dāng)我...
    茶點故事閱讀 67,942評論 6 392
  • 文/花漫 我一把揭開白布跳昼。 她就那樣靜靜地躺著,像睡著了一般援所。 火紅的嫁衣襯著肌膚如雪庐舟。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,727評論 1 305
  • 那天住拭,我揣著相機與錄音挪略,去河邊找鬼。 笑死滔岳,一個胖子當(dāng)著我的面吹牛杠娱,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播谱煤,決...
    沈念sama閱讀 40,447評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼摊求,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了刘离?” 一聲冷哼從身側(cè)響起室叉,我...
    開封第一講書人閱讀 39,349評論 0 276
  • 序言:老撾萬榮一對情侶失蹤睹栖,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后茧痕,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體野来,經(jīng)...
    沈念sama閱讀 45,820評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,990評論 3 337
  • 正文 我和宋清朗相戀三年踪旷,在試婚紗的時候發(fā)現(xiàn)自己被綠了曼氛。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,127評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡令野,死狀恐怖舀患,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情气破,我是刑警寧澤聊浅,帶...
    沈念sama閱讀 35,812評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站堵幽,受9級特大地震影響狗超,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜朴下,卻給世界環(huán)境...
    茶點故事閱讀 41,471評論 3 331
  • 文/蒙蒙 一努咐、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧殴胧,春花似錦渗稍、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至灸姊,卻和暖如春拱燃,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背力惯。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評論 1 272
  • 我被黑心中介騙來泰國打工碗誉, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人父晶。 一個月前我還...
    沈念sama閱讀 48,388評論 3 373
  • 正文 我出身青樓哮缺,卻偏偏與公主長得像,于是被迫代替她去往敵國和親甲喝。 傳聞我的和親對象是個殘疾皇子尝苇,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,066評論 2 355

推薦閱讀更多精彩內(nèi)容