1. 程式人生 > >Dijkstra演算法、prim演算法和 Kruskal演算法詳解

Dijkstra演算法、prim演算法和 Kruskal演算法詳解

1 Dijkstra演算法

問題描述:在一個圖中,給定指定頂點,求該頂點到其它頂點的最短距離。


如圖所示:這是一個有向圖,現在要求解從頂點V1到其它頂點的最短距離。以上圖為例,利用Dijkstra演算法求解最短距離。

步驟:

(1)將所有頂點分為兩組,一組是未知的即為S,一組是已知的記為W。開始時,S={V1,V2,V3,V4,V5,V6,V7},W={};

(2)首先選擇頂點V1到其它頂點中距離最短的頂點為已知頂點。顯然V1->v1=0為最小值。這時S={V2,V3,V4,V5,V6,V7},W={V1};

更新距離表格:


(3)接著在已知的距離中,v1->v4的距離最短,將頂點4放入已知的序列中。這時S={V2,V3,V5,V6,V7},W={V1,V4},更新距離表格。


(4) 重複上述過程,在未知頂點中,選擇距離最小的作為已知的,V1->V2=2是最小的,選擇V2作為已知的。此時,S={V3,V5,V6,V7},W={V1,V4,V2},更新距離。


(5)重複上述過程,分別是V5和V3被選為已知的,此時,S={V6,V7},W={V1,V4,V2,V5,V3}。更新距離表格後得到:


(6)比較可知,選擇V7作為已知的,此時,S={V6},W={V1,V4,V2,V5,V3,V7}。更新距離表格後得到:


(7)最後選擇V6,更新距離,演算法結束。最終結果如下圖所示:


具體程式碼如下:

void Dijkstra(const vector<vector<int>>& path, vector<bool>& flag,vector<int>& res,int v)
{
    const int n=flag.size();
    for(int i=0;i<n;++i)
    {
        res[i]=path[v][i];
    }
    flag[v]=true;
    for(int i=0;i<n;++i)
    {
        int tmp=maxint;// const int maxint=INT_MAX
        int u=v;
        for(int j=0;j<n;++j)
        {
            if(!flag[j]&&res[j]<tmp)
            {
               u=j;
               tmp=res[j];
            }
        }
        flag[u]=true;
        for(int j=0;j<n;++j)
        {
            if(!flag[j]&&path[u][j]<maxint)
            {
                res[j]=min(res[j],res[u]+path[u][j]);
            }
        }
    }
}

2 prim演算法

計算最小生成樹採用prim演算法。在每一步,將節點當做根並往上加邊,將相關頂點增加到增長的樹上。在演算法的每一個階段都可以通過選擇邊(u,v),使得(u,v)的值是所有u在樹上但v不在樹上的邊的值的最小者,從而找到一個新的頂點並將它新增到這棵樹中。


程式碼如下:

void prim(const vector<vector<int>>& path, vector<bool>& flag,vector<int>& res,int v)
{
    const int n=flag.size();
    for(int i=0;i<n;++i)
    {
        res[i]=path[v][i];
    }
    flag[v]=true;
    for(int i=0;i<n;++i)
    {
        int u=-1;
        int tmp=maxint;//const int maxint=INT_MAX;
        for(int j=0;j<n;++j)
        {
            if(!flag[j]&&res[j]<tmp)
            {
                u=j;
                tmp=res[j];
            }
        }
        flag[u]=true;
        for(int j=0;j<n;++j)
        {
            if(!flag[j]&&path[u][j]!=maxint)
            {
                res[j]=min(res[j],path[u][j]);
            }
        }
    }
}

3 kruskal演算法

和prim演算法類似,每次都是尋找權值最短的一條邊。可以這樣看:開始存在n顆單節點樹,每次找到權值最短的一棵樹將其合併起來,但是注意不要形成環。最後只剩下一棵樹的時候,代表合併完成。

程式碼如下:

bool cmp(pair<pair<int,int>,int> a,pair<pair<int,int>,int> b)
{
    return a.second<=b.second;
}
bool isSame(vector<pair<pair<int,int>,bool>>& flag,pair<int,int> t)
{
    int x=t.first;
    int y=t.second;
    for(int i=x+1;i<y;++i)
    {
        if(flag.find(make_pair<make_pair(x,i),true>)!=flag.end()&&flag.find(make_pair<make_pair(i,y),true>)!=flag.end())
        {
            return true;
        }
    }
    return false;
}
void krustral(const vector<vector<int>>& path,vector<pair<pair<int,int>,bool>>& flag,vector<int>& res)
{
    const int n=flag.size();
    vector<pair<pair<int,int>,int>> m;
    for(int i=0;i<n;++i)
    {
        for(int j=i+1;j<n;++j)
        {
            if(path[i][j]!=maxint)
            {
                m.push_back(make_pair(make_pair(i,j),path[i][j]));
               // flag.push_back(make_pair(make_pair(i,j),false));
            }
        }
    }
    sort(m.begin(),m.end(),cmp);
    int count=0;
    for(int i=0;i<m.size();++i)
    {
        if(!isSame(flag,m[i].first))
        {
            res.push_back(m[i].second);
            flag.push_back(make_pair(m[i].first,true));
            ++count;
            if(count==n)
                return;
        }
    }
    
}

相關推薦

原碼反碼補碼的

原碼 原碼就是符號位加上真值的絕對值, 即用第一位表示符號, 其餘位表示值. 比如如果是8位二進位制: [+1]原 = 0000 0001 [-1]原 = 1000 0001 第一位是符號位. 因為第一位是符號位, 所以8位二進位制數的取值範圍就是: [1111 1111

裝置裝置節點裝置驅動

1.裝置 Linux下的裝置通常分為三類,字元裝置,塊裝置和網路裝置。 裝置驅動程式也分為對應的三類:字元裝置驅動程式、塊裝置驅動程式和網路裝置驅動程式。 常見的字元裝置有滑鼠、鍵盤、串列埠、控制檯等。 常見的塊裝置有各種硬碟、flash磁碟、RAM磁碟等。 在

PHP中的單引號雙引號轉義字元

PHP單引號及雙引號均可以修飾字符串型別的資料,如果修飾的字串中含有變數(例$name);最大的區別是: 雙引號會替換變數的值,而單引號會把它當做字串輸出。 轉義字元,顧名思義會將規定的語法用"\"來輸出。但語法規定在不同的系統中轉義字元的作用不同,例如:windows下的回車換行符用"\r"或"

Android開發——View動畫幀動畫屬性動畫

0. 前言Android動畫是面試的時候經常被問到的話題。我們都知道Android動畫分為三類:View動畫、幀動畫和屬性動畫。先對這三種動畫做一個概述:View動畫是一種漸進式動畫,定義動畫開始和結束

Java中編譯期執行期堆記憶體棧記憶體

java中記憶體分配策略及堆和棧的比較    1 記憶體分配策略    按照編譯原理的觀點,程式執行時的記憶體分配有三種策略,分別是靜態的,棧式的,和堆式的.    靜態儲存分配是指在編譯時就能確定每個資料目標在執行時刻的儲存空間需求,因而在編譯時就可以給他們分配固定的記憶體空間.這種分配策略要求程式程式碼中

Eureka的服務提供者服務消費者註冊中心

一 架構圖二 服務提供者1 服務註冊“服務提供者”在啟動的時候會通過REST請求的方式將自己註冊到Eureka Server上,同時帶上自身服務的一些元資料資訊。Eureka Server接收到這個REST請求之後,將元資料資訊儲存在一個雙層結構Map中,其中第一層的key是

Spring之IOC核心容器Bean概念

    這一週忙了很多與程式碼無關的事,感覺心態上還是有些急躁,週中挑幾個晚上看了一些文章,上午起來總結了一下,下午開始寫部落格,因為沒有時間擼程式碼,所以就打算先把看到的概念梳理梳理,磨刀不誤砍柴工。    首先來看一看什麼是IOC,他的全稱是Inversion of Co

關於AngularJs中$http postget 傳送接受引數

1、POST、GET攜帶引數的寫法不一樣,如下: ? 1 2 3 4 5 6 7 $http({method: 'post', url: './feedback/ma

為什麼C++中常量引用可以繫結非常量的物件字面值一般表示式

    在c++語言中,除兩種例外情況,其他引用的型別都要和與之繫結的物件嚴格匹配,如int型的引用只能繫結int型的物件;並且引用不能直接與字面值常量或表示式結果繫結。    其中一種例外情況是:初始化常量引用時,允許用任意表達式作為初始值,只要該表示式的結果能轉換成引用的

Android Drawable資源中selectorlayer-listshape標籤

在實際開發中,我們經常會對控制元件的樣式進行一些修改已滿足我們的要求,這時候就會引用 Drawable 資源的樣式檔案。 1、StateListDrawable 資源         StateListDrawable 用於組織多個 Drawable 物件。當使用 Stat

Dijkstra演算法prim演算法 Kruskal演算法

1 Dijkstra演算法問題描述:在一個圖中,給定指定頂點,求該頂點到其它頂點的最短距離。如圖所示:這是一個有向圖,現在要求解從頂點V1到其它頂點的最短距離。以上圖為例,利用Dijkstra演算法求解最短距離。步驟:(1)將所有頂點分為兩組,一組是未知的即為S,一組是已知的

最小生成樹的prim演算法kruskal演算法

轉載自:勿在浮沙築高臺http://blog.csdn.net/luoshixian099/article/details/51908175 關於圖的幾個概念定義: 連通圖:在無向圖中,若任意兩個頂點vi與vj都有路徑相通,則稱該無向圖為連通圖。 強連通圖:在有向圖中,若任意兩個

primKruskal演算法

prim演算法 1 #include <iostream> 2 #include <cstdio> 3 #define max 10 4 using namespace std; 5 typedef struct 6 { 7 int relat

Project-2: Prim Kruskal 演算法尋找最小生成樹

Prim 和 Kruskal 演算法尋找最小生成樹 實驗原理 堆 堆是一種經過排序的完全二叉樹,其中任一非終端節點的資料值均不大於(或不小於)其左子節點和右子節點的值。最大堆和最小堆是二叉堆的兩種形式。最大堆:根結點的鍵值是所有堆結點鍵值中最大者。最小堆:

python機器學習案例系列教程——最小生成樹(MST)的Prim演算法Kruskal演算法

最小生成樹MST 一個有 n 個結點的連通圖的生成樹是原圖的極小連通子圖,且包含原圖中的所有 n 個結點,並且有保持圖連通的最少的邊。 也就是說,用原圖中有的邊,連線n個節點,保證每個節點都被連線,且使用的邊的數目最少。 最小權重生成樹 在一給定

圖的最小生成樹:Prim演算法Kruskal演算法

1. 圖的最小生成樹 生成樹的定義:如果連通圖G的一個子圖是一棵包含G的所有頂點的樹,則該子圖稱為G的生成樹。 生成樹是連通圖的包含圖中的所有頂點的極小連通子圖。它並不唯一,從不同的頂點出發進行遍歷,可以得到不同的生成樹。 其中,權值最小的樹就是最小生成樹

Prim演算法Kruskal演算法理解

一:Prim演算法 Prim演算法的實現就是通過搜尋來實現的,首先找一個起始點a,然後找與起始點相關聯的所有的點中離a最近的點b,並且把這個點融入最小生成樹中,然後再比較與b相關聯的點和與a相關聯的點的距離,若可以更新點,則更新然後繼續找! 拿一道poj的題來說 You

PrimKruskal演算法之C++實現

最近好長時間都困惑在這兩個演算法中,其實也不難,就是寫的時候比較費勁。現在總結一下。 首先說一下兩個演算法是幹嘛呢? 都是求解一個無向圖G的最小生成樹(minimum spanning tree),就是由該圖的那些連線G的所有頂點的邊構成的樹,其總值最低。這

最小生成樹演算法——Prim演算法Kruskal演算法的JS實現

之前都是看書,大部分也是c++的實現,但是搞前端不能忘了JS啊,所以JS實現一遍這兩個經典的最小生成樹演算法。 一、權重圖和最小生成樹 權重圖:圖的邊帶權重 最小生成樹:在連通圖的所有生成樹中,所有邊的權重和最小的生成樹 本文使用的圖如下: 它的最小生成樹如下:

最小生成樹的兩種經典演算法--prim演算法kruskal演算法

一個連通圖的生成樹是圖的一個極小連通子圖,它包含所有頂點,但只有足以構成樹的n-1條邊 這意味著對生成樹來說,砍去它的任何一條邊,就會使生成樹變成非連通圖,若給他增加一條邊就會形成一條迴路 最小生成樹:權值最小的那顆生成樹叫~ 最小生成樹的性質: 最小生成樹