prim 與dijkstra的異同 POJ 2485 Highways

來源:互聯網
上載者:User

題目連結:http://poj.org/problem?id=2485

題意:一個地方F,沒有Highways,交通不便,要建 Highways,每個Highway串連兩個城鎮,所有的Highways都是直線的。

範例輸入意思:

T  案例數

N 城鎮數

下面N行N列,以矩陣的形式

     v1   v2    v3

v1  0    990  692 

v2 990   0    179

v3 692  179   0

範例輸出意思:

明顯路徑是 v1-v3-v2,路徑中最大的數是692,輸出的就是它

思路:

最小產生樹問題,一般用prim,kuskal演算法 。prim演算法是以頂點來擴充的。把每次找到的頂點加入頂點集U,然後下次再找與U相鄰且最小的頂點,加入U,依次,得到最小產生樹。

參考:http://en.wikipedia.org/wiki/Prim's_algorithm

#include <stdio.h>#include <string.h>#define M  502#define INF 99999int prim[M][M];int visit[M];int Len[M];  //Len[i] 記錄頂點集U到i的最短距離,注意區別dijkstra中的dis[i]int n;int ans;int  prim_solve(int xx){    int minx;    int i,j,k;    memset(visit,0,sizeof(visit));  //開始時都未訪問    ans = -1;    for (i = 1; i <= n; i++)    {        Len[i] = prim[xx][i];    }    Len[xx] = 0;    visit[xx] = 1;  //此時U中只有起點xx    for(i = 1; i< n; i++)  // 注意:不能=,因為xx起點已經訪問過,所以只需再訪問n-1個    {        minx = INF;        for(j = 1; j <= n; j++ )   //很像dijkstra中的吧,但注意:這裡的Len[i]與dijkstra中dis[i]意義相當不同        {                          //這裡找的是:與頂點集U相鄰的距離最小值            if ( !visit[j]  && Len[j] < minx)            {                minx = Len[j];                k = j;            }        }        visit[k] = 1;   //找到,加入U        if (ans < minx)   //儲存最短路徑中最大的一條邊,比如範例中692        {            ans = minx;        }        //i=1時,U中只有起點xx和新加入的k,Len[j]與prim[j]比較:就是比較xx到j的距離和新加入U的k頂點到j的距離        //之後,Len[j]就是U到j的最短距離啦,這樣把U中所有頂點看成一個,Len[j]就是U到j(V-U中任意一個)的最短距離        //以此類推,i>1 時,每次都把原來的頂點集U到j的距離和新加入的k到j的距離比較,這樣得到了新U到j的最短距離        //從而,就得到了新U到V-U中任一頂點的距離,儲存在 Len中        for (j = 1; j <= n; j++)           {            if ( !visit[j] && Len[j] > prim[k][j])            {                Len[j] = prim[k][j];            }        }    }    return ans;}int main(){    int T;    int i,j;    scanf("%d",&T);    while(T--)    {        memset(prim,0,sizeof(prim));        scanf("%d",&n);        for(i = 1; i <= n; i++)            for(j = 1; j <= n; j ++)            {                scanf("%d",&prim[i][j]);            }        printf("%d\n",prim_solve(1)); //以第一個頂點開始,也可以是其他,無所謂,改成2。。。。一樣    }    return 0;}

你會覺得prim代碼實現是來很像dijkstra,參考http://blog.csdn.net/bill_ming/article/details/7578037

prim是計算最小產生樹的演算法,dijkstra是計算最短路徑的演算法。

他們都是從幾何V-U中不斷選出權值最小的頂點加入U,那他們是否可以互用嗎?

必然不可以嘛!

他們的不同之處是:

prim是把U中的點看成一個整體,每次尋找V-U中和U距離最小的頂點加入U。而dijkstra是相對於源點V0而言的,每次尋找的是V-U中裡V0最近的頂點。

所以:

dijkstra中dis[i]記錄的是V0到i的最短距離。

用這樣的for迴圈來更新dis,結果dis[j]是比較源點V0直接到j   和   源點V0經過k到j的最短距離所得結果

 for(j = 1; j <= n; j++)   
        {
            if ( !visit[j] && dis[j] > dis[k] + map[k][j])
            {
                dis[j] = dis[k] + map[k][j];
            }
        }

而prim中Len[i]記錄的是頂點集U(看成整體)到i的最短距離

用這樣的for迴圈來更新頂點集U到V-U中任一頂點的距離,比較的是加入k之前頂點集到j的距離  和 k 到j的距離 。

得到的就是包含k的新頂點集U到j的最短距離。   (感謝羅康琦大牛!!!)

//i=1時,U中只有起點xx和新加入的k,Len[j]與prim[j]比較:就是比較xx到j的距離和新加入U的k頂點到j的距離
        //之後,Len[j]就是U到j的最短距離啦,這樣把U中所有頂點看成一個,Len[j]就是U到j(V-U中任意一個)的最短距離
        //以此類推,i>1 時,每次都把原來的頂點集U到j的距離和新加入的k到j的距離比較,這樣得到了新U到j的最短距離
        //從而,就得到了新U到V-U中任一頂點的距離,儲存在 Len中
        for (j = 1; j <= n; j++)   
        {
            if ( !visit[j] && Len[j] > prim[k][j])
            {
                Len[j] = prim[k][j];
            }
        }

他們的區別就知道了。所以不能互用啊,prim還是乖乖算最小產生樹吧,dijkstra還是繼續管計算最短路徑吧

舉個例子就知道他們不能亂來了:

有四個頂點(v0,
v1, v2, v3)和四條邊且邊值定義為(v0,
v1)=20, (v0, v2)=10, (v1, v3)=2, (v3, v2)=15的圖,用Prim演算法得到的最小產生樹中v0跟v1是不直接相連的,也就是在最小產生樹中v0v1的距離是v0->v2->v3->v1的距離是27,而用Dijkstra演算法得到的v0v1的距離是20,也就是二者直接連線的長度。


SO。。。。



聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.