1. 程式人生 > >【圖論】最短路徑

【圖論】最短路徑

最短路徑問題(floyed.cpp dijkstra.cpp)

題目描述
平面上有n個點(n<=100),每個點的座標均在-10000~10000之間。其中的一些點之間有連線。若有連線,則表示可從一個點到達另一個點,即兩點間有通路,通路的距離為兩點間的直線距離。現在的任務是找出從一點到另一點之間的最短路徑。


輸入
第1行:1個整數n

第2..n+1行:每行2個整數x和y,描述了一個點的座標

第n+2行:1個整數m,表示圖中連線的數量

接下來有m行,每行2個整數i和j,表示第i個點和第j個點之間有連線

最後1行:2個整數s和t,分別表示源點和目標點

輸出
第1行:1個浮點數,表示從s到t的最短路徑長度,保留2位小數

樣例輸入
5
0 0
2 0
2 2
0 2
3 1
5
1 2
1 3
1 4
2 5
3 5
1 5

樣例輸出
3.41


--------------------------------------------------------------------


我們可以用勾股定理,將每兩個點的權值算出來(兩點之間沒有邊的為∞),完成構圖。


---------------------------------------------------------------------


求最短路的四種演算法(u[i][j]為連線i與j的邊的權值, dis[i][j]為從i到j的最短路徑長度,dis[i]為從起點至i的最短路徑,s為起點,e為終點):

一、Floyd演算法

       演算法步驟:

                      1、初始化。使dis[i][j] = u[i][j];

                      2、依次列舉中間點k;

                      3、如果dis[i][j] > dis[i][k] + dis[k][j],則將dis[i][j]替換;

                      4、dis[s][e]為最終答案。

       注意:外層迴圈一定要列舉k。

for(int k = 1; k <= n; k++)
{
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= n; j++)
            dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
    }
}

二、Dijkstra演算法

      演算法步驟:

                      1、初始化。使dis[i] = u[s][i];

                      2、從所有未被訪問的節點中選擇dis最小的那一個;

                      3、重新計算dis[i]的最短路徑長;

                      4、給現在被選中的節點打上標記。

        5、dis[e]為最終答案。


for(int i = 1; i <= n; i++)
{
    int p = 0, j, mins = 1 << 30;
    for(j = 1; j <= n; j++)
    {
        if(!v[j] && dis[j] < mins)
            p = j, mins = dis[j];
    }
    if(!p)
        return 0;
    v[p] = 1;
    for(j = 1; j <= n; j++)
        dis[j] = min(dis[j], dis[p] + u[p][j]);
}


三、Bellman-Ford演算法

演算法步驟:

1、給每一個點編號;

2、依次每句每一條邊,更新dis[i]的最短距離;

3、dis[e]為最終答案。

for(int i = 1; i <= n; i++)
{
    for(int j = 1; j <= E; j++)
        dis[v] = min(dis[v], dis[u] + w[j]); //u和p表示gaibian
}

四、SPFA演算法

演算法步驟:

1、將目前的點加入佇列;

2、取出隊首元素;

3、若通過該點可更新另一個點dis[i]的值,則進行4,否則執行3,直到連線該點的所有邊列舉完;

4、若該點不在佇列中,則將該點加入佇列;

5、dis[e]為最後答案。

for(int i = 1; i <= n; i++)
{
    int p = queue.front();
    queue.pop();
    v[p] = 0;
    for(int j = 1; j <= n; j++)
    {
        if(dis[j] > dis[p] + w[p][j])
        {
            dis[j] = dis[p] + w[p][j];
            if(!v[j])
            {
                v[j] = 1;
                queue.push(j);
            }
        }
    }