最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++中的最小生成樹算法超詳細(xì)教程

 更新時(shí)間:2023年08月23日 09:56:59   作者:吃代碼的喵醬-i  
這篇文章主要介紹了C++中的最小生成樹算法超詳細(xì)教程,最小生成樹的最著名的算法有兩個(gè), 一個(gè)是Prim算法, 另一個(gè)當(dāng)然就是Kruskal算法, 接下來, 我將盡我所能的介紹這兩個(gè)算法, 也算是對自己學(xué)習(xí)的一個(gè)回顧吧,需要的朋友可以參考下

前言

最小生成樹的最著名的算法有兩個(gè), 一個(gè)是 Prim 算法, 另一個(gè)當(dāng)然就是 Kruskal 算法, 接下來, 我將盡我所能的介紹這兩個(gè)算法, 也算是對自己學(xué)習(xí)的一個(gè)回顧吧

老規(guī)矩, 模板題如下

題目背景

Farmer John 被選為他們鎮(zhèn)的鎮(zhèn)長!他其中一個(gè)競選承諾就是在鎮(zhèn)上建立起互聯(lián)網(wǎng),并連接到所有的農(nóng)場。當(dāng)然,他需要你的幫助。

題目描述

FJ 已經(jīng)給他的農(nóng)場安排了一條高速的網(wǎng)絡(luò)線路,他想把這條線路共享給其他農(nóng)場。為了用最小的消費(fèi),他想鋪設(shè)最短的光纖去連接所有的農(nóng)場。

你將得到一份各農(nóng)場之間連接費(fèi)用的列表,你必須找出能連接所有農(nóng)場并所用光纖最短的方案。每兩個(gè)農(nóng)場間的距離不會(huì)超過105。

輸入格式

第一行農(nóng)場的個(gè)數(shù)N(3 ≤ N ≤ 100)

接下來是一個(gè)N×N的矩陣,表示每個(gè)農(nóng)場之間的距離。理論上,他們是N行,每行由N個(gè)用空格分隔的數(shù)組成,實(shí)際上,由于每行8080個(gè)字符的限制,因此,某些行會(huì)緊接著另一些行。當(dāng)然,對角線將會(huì)是00,因?yàn)椴粫?huì)有線路從第i個(gè)農(nóng)場到它本身。

輸出格式

只有一個(gè)輸出,其中包含連接到每個(gè)農(nóng)場的光纖的最小長度。

輸入輸出樣例

輸入 #1

4
0 4 9 21
4 0 8 17
9 8 0 16
21 17 16 0

輸出 #1

28

Kruskal 算法

首先, 介紹我更喜歡的, 也是相對更容易敲代碼的 Kruskal 算法

按照離散數(shù)學(xué)的定義

> 基本思想:按照權(quán)值從小到大的順序選擇n-1條邊,并保證這n-1條邊不構(gòu)成回路。

> 具體做法:首先構(gòu)造一個(gè)只含n個(gè)頂點(diǎn)的森林,然后依權(quán)值從小到大從連通網(wǎng)中選擇邊加入到森林中,并使森林中不產(chǎn)生回路,直至森林變成一棵樹為止。

故我們可以提煉出算法的流程如下

  • 將邊升序排序
  • 判斷是否能插入此邊,插入后做:
    • inc(ans,路徑長度)
    • 合并連通分支

1.對于排序, 可以借助于庫函數(shù)sort

2.對于判斷是否可以插入的步驟, 我們的想法是借助于并查集, 如果這條邊的兩個(gè)祖先相同, 那么插入這條邊顯然會(huì)構(gòu)成環(huán), 故跳過

3.算法結(jié)束的標(biāo)志是加入的邊的數(shù)目為n - 1

算法已經(jīng)介紹清楚了, 那么下面我們就來考慮一下存儲(chǔ)邊的數(shù)據(jù)結(jié)構(gòu), 我們選擇了如下所示的結(jié)構(gòu)體數(shù)組

struct Edge {
    int u; //起點(diǎn)
    int v; //終點(diǎn)
    int w; //權(quán)值
} e[100010];

對于并查集的處理就簡單的提一下

1. 初始化

void init() {
    for (int i = 1; i <= n; i++) {
        fa[i] = i;
    }
}

2.尋找祖先的函數(shù), 路徑壓縮算法

int find (int x) {
    return fa[x] == x ? fa[x] : fa[x] = find(fa[x]);
}

3.合并操作, 將兩個(gè)屬于不同集合的頂點(diǎn)合并到同一個(gè)集合, 即入贅操作

void union_(int x, int y) {
    int fx = find(x);
    int fy = find(y);
    fa[fx] = fy;
}

感覺也沒多少東西, 那就直接貼完整AC代碼吧

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 100 + 10;
int n, cnt, fa[MAXN], sum, ans;
void init() {
    for (int i = 1; i <= n; i++) {
        fa[i] = i;
    }
}
int find (int x) {
    return fa[x] == x ? fa[x] : fa[x] = find(fa[x]);
}
void union_(int x, int y) {
    int fx = find(x);
    int fy = find(y);
    fa[fx] = fy;
}
struct Edge {
    int u;
    int v;
    int w;
} e[100010];
bool cmp (Edge a, Edge b) {
    return a.w < b.w;
}
//這一題應(yīng)該采用并查集來判斷是否會(huì)構(gòu)成一個(gè)環(huán), 然后用一個(gè)結(jié)構(gòu)體數(shù)組來存儲(chǔ)邊的信息
int main() {
    cin >> n;
    init();
    int h;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            cin >> h;
            if (j > i) {
                //存一半就可以了
                e[++cnt].u = i;
                e[cnt].v = j;
                e[cnt].w = h;
            }
        }
    }
    sort(e + 1, e + 1 + cnt, cmp);
    for (int i = 1; i <= cnt; i++) {
        int u = e[i].u;
        int v = e[i].v;
        if (find(u) != find(v)) {
            union_(u, v);
            sum++;
            ans += e[i].w;
            if (sum == n - 1) {
                break;
            }
        }
    }
    cout << ans;
    return 0;
}

Prime 算法

Prim 算法也是一個(gè)貪心算法, 它和 Kruskal 算法的區(qū)別在于 Prim 算法是每次從一個(gè)點(diǎn)出發(fā)選擇當(dāng)前點(diǎn)的不構(gòu)成環(huán)的最小的邊, 而 Kruskal 算法是從全局的角度, 從所有的邊中選擇不構(gòu)成環(huán)的最小的邊, 所以 Prim 算法相對而言復(fù)雜一些 很顯然, 每次都要從當(dāng)前的頂點(diǎn)選擇最優(yōu)的邊, 那么這就是一個(gè)很耗時(shí)的操作, 于是我們可以對這一步進(jìn)行堆優(yōu)化(其實(shí)就是使用 優(yōu)先隊(duì)列 ) 這個(gè)算法的數(shù)據(jù)結(jié)構(gòu)相對復(fù)雜一些, 接下來我來介紹一下

bool vis[MAXN]; //用來判斷這個(gè)頂點(diǎn)是否訪問過
struct Edge {
    int u; //起點(diǎn)
    int v; //終點(diǎn)
    int w; //權(quán)值
    bool operator <(const struct Edge& n) const {
        return w > n.w;
    } //重載比較運(yùn)算符, 用于后面的優(yōu)先隊(duì)列
};
vector <Edge> g[MAXN]; //向量數(shù)組, 用于存放每一個(gè)頂點(diǎn)所連接的邊的信息
priority_queue <Edge> edge; //優(yōu)先隊(duì)列不解釋

1.讀取數(shù)據(jù)

for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= n; j++) {
        int w;
        cin >> w;
        if (w == 0) continue;
        g[i].push_back(Edge{i, j, w});
    }
}

2.以1為起始點(diǎn), 將其相連邊入隊(duì)

vis[1] = true;
for (int i = 0; i < g[1].size(); i++) {
    edge.push(g[1][i]);
}

3.執(zhí)行 Prim算法, 直到邊數(shù)為n - 1為止

 while (cnt < n - 1){
    int w = edge.top().w;
    int v = edge.top().v;
    edge.pop();
    if (vis[v]) {
        //已經(jīng)訪問過了
        continue;
    }
    vis[v] = true;
    ans += w; //ans是結(jié)果
    cnt++; //cnt是邊的計(jì)數(shù)器
    for (int i = 0; i < g[v].size(); i++) {
        if (!vis[g[v][i].v]) {
            edge.push(g[v][i]);
        }
    }
}

到此這篇關(guān)于C++中的最小生成樹算法超詳細(xì)教程的文章就介紹到這了,更多相關(guān)C++中的最小生成樹算法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C++ 算法精講之貪心算法

    C++ 算法精講之貪心算法

    貪心算法(又稱貪婪算法)是指,在對問題求解時(shí),總是做出在當(dāng)前看來是最好的選擇。也就是說,不從整體最優(yōu)上加以考慮,他所做出的僅是在某種意義上的局部最優(yōu)解
    2022-03-03
  • C語言解決百錢買百雞問題

    C語言解決百錢買百雞問題

    本文給大家分享的是一個(gè)經(jīng)典的算法(百元百雞)的C語言版的解決方法,使用的是比較偷懶的窮舉法,有需要的小伙伴可以參考下。
    2016-02-02
  • C++中高性能內(nèi)存池的實(shí)現(xiàn)詳解

    C++中高性能內(nèi)存池的實(shí)現(xiàn)詳解

    在 C/C++ 中,內(nèi)存管理是一個(gè)非常棘手的問題,我們在編寫一個(gè)程序的時(shí)候幾乎不可避免的要遇到內(nèi)存的分配邏輯。本文將通過C++實(shí)現(xiàn)高性能內(nèi)存池,感興趣的可以了解一下
    2022-10-10
  • C語言實(shí)現(xiàn)圖片放大縮小

    C語言實(shí)現(xiàn)圖片放大縮小

    這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)圖片放大縮小,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • 使用C++實(shí)現(xiàn)MySQL數(shù)據(jù)庫連接池

    使用C++實(shí)現(xiàn)MySQL數(shù)據(jù)庫連接池

    這篇文章主要為大家詳細(xì)介紹了如何使用C++實(shí)現(xiàn)MySQL數(shù)據(jù)庫連接池,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,有需要的小伙伴可以了解下
    2024-03-03
  • C語言詳細(xì)講解樹狀數(shù)組與線段樹

    C語言詳細(xì)講解樹狀數(shù)組與線段樹

    顧名思義,樹狀數(shù)組就是用數(shù)組來模擬樹形結(jié)構(gòu)唄。那么衍生出一個(gè)問題,為什么不直接建樹,因?yàn)闃錉顢?shù)組能處理的問題就沒必要建樹。線段樹是一種二叉搜索樹,與區(qū)間樹相似,它將一個(gè)區(qū)間劃分成一些單元區(qū)間,每個(gè)單元區(qū)間對應(yīng)線段樹中的一個(gè)葉結(jié)點(diǎn)
    2022-04-04
  • C/C++計(jì)算程序執(zhí)行時(shí)間的幾種方法實(shí)現(xiàn)

    C/C++計(jì)算程序執(zhí)行時(shí)間的幾種方法實(shí)現(xiàn)

    本文主要介紹了C/C++計(jì)算程序執(zhí)行時(shí)間的幾種方法實(shí)現(xiàn),包括使用clock()函數(shù)、使用庫和使用time.h頭文件中的time()函數(shù),具有一定的參考價(jià)值,感興趣的可以了解一下
    2025-02-02
  • 使用QGraphicsView實(shí)現(xiàn)氣泡聊天窗口+排雷功能

    使用QGraphicsView實(shí)現(xiàn)氣泡聊天窗口+排雷功能

    這篇文章主要介紹了使用QGraphicsView實(shí)現(xiàn)氣泡聊天窗口+排雷,重點(diǎn)給大家介紹使用QWebEngineView控件內(nèi)嵌html+CSS的實(shí)現(xiàn)方式,需要的朋友可以參考下
    2022-04-04
  • C語言結(jié)構(gòu)體(struct)的詳細(xì)講解

    C語言結(jié)構(gòu)體(struct)的詳細(xì)講解

    C語言中,結(jié)構(gòu)體類型屬于一種構(gòu)造類型(其他的構(gòu)造類型還有:數(shù)組類型,聯(lián)合類型),下面這篇文章主要給大家介紹了關(guān)于C語言結(jié)構(gòu)體(struct)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-03-03
  • C語言實(shí)現(xiàn)的一個(gè)三子棋游戲詳解流程

    C語言實(shí)現(xiàn)的一個(gè)三子棋游戲詳解流程

    三子棋是一種民間傳統(tǒng)游戲,又叫九宮棋、圈圈叉叉、一條龍、井字棋等。將正方形對角線連起來,相對兩邊依次擺上三個(gè)雙方棋子,只要將自己的三個(gè)棋子走成一條線,對方就算輸了
    2021-10-10

最新評論

凤山市| 海林市| 太原市| 厦门市| 广水市| 田东县| 荆州市| 海门市| 包头市| 桃园县| 梅州市| 诸暨市| 邮箱| 同仁县| 华蓥市| 平阴县| 普陀区| 两当县| 镇平县| 兴隆县| 宁南县| 义乌市| 禄丰县| 当涂县| 永登县| 安徽省| 和静县| 屏南县| 永善县| 普兰店市| 轮台县| 南通市| 琼海市| 衡阳县| 萝北县| 察隅县| 惠安县| 德保县| 大方县| 佛学| 句容市|