SSL 1613最短路徑問題

2021-10-13 18:19:21 字數 4592 閱讀 9221

time limit:1000ms

memory limit:65536k

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

輸入檔案short.in,共有n+m+3行,其中:

第一行為乙個整數n。

第2行到第n+1行(共n行),每行的兩個整數x和y,描述乙個點的座標(以乙個空格隔開)。

第n+2行為乙個整數m,表示圖中的連線個數。

此後的m行,每行描述一條連線,由兩個整數i,j組成,表示第i個點和第j個點之間有連線。

最後一行:兩個整數s和t,分別表示源點和目標點。

輸出檔案short.out僅一行,乙個實數(保留兩位小數),表示從s到t的最短路徑的長度。

500

2022

0231

5121

3142

5351

5

3.41
用floyd(弗洛伊德)演算法,是最簡單的最短路徑演算法,可以計算圖中任意兩點間的最短路徑。floyd的時間複雜度是o (n3),適用於出現負邊權的情況。

演算法描述:

初始化:點u、v如果有邊相連,則dis[u][v]=w[u][v]。

如果不相連則dis[u][v]=0x7fffffff

for (k =

1; k <= n; k++

) for (i =

1; i <= n; i++

) for (j =

1; j <= n; j++

) if (

(i != j)

&&(i != k)

&&(j != k)

&&(dis[i]

[j]>dis[i]

[k]+ dis[k]

[j])

) dis[i]

[j]= dis[i]

[k]+ dis[k]

[j];

演算法結束:dis[i][j]得出的就是從i到j的最短路徑。

演算法分析&思想講解:

三層迴圈,第一層迴圈中間點k,第二第三層迴圈起點終點i、j,演算法的思想很容易理解:如果點i到點k的距離加上點k到點j的距離小於原先點i到點j的距離,那麼就用這個更短的路徑長度來更新原先點i到點j的距離。

在上圖中,因為dis[1][3]+dis[3][2]3)。

用來計算從乙個點到其他所有點的最短路徑的演算法,是一種單源最短路徑演算法。也就是說,只能計算起點只有乙個的情況。

dijkstra的時間複雜度是o (n2),它不能處理存在負邊權的情況。

演算法描述:

設起點為s,dis[v]表示從s到v的最短路徑,pre[v]為v的前驅節點,用來輸出路徑。

a)初始化:dis[v]=∞(v≠s); dis[s]=0; pre[s]=0;

b)for (i = 1; i <= n ; i++)

1.在沒有被訪問過的點中找乙個頂點u使得dis[u]是最小的。

2.u標記為已確定最短路徑

3.for 與u相連的每個未確定最短路徑的頂點v

if (dis[u]+w[u][v] < dis[v])

c)演算法結束:dis[v]為s到v的最短距離;pre[v]為v的前驅節點,用來輸出路徑。

演算法分析&思想講解:

從起點到乙個點的最短路徑一定會經過至少乙個「中轉點」(例如下圖1到5的最短路徑,中轉點是2。特殊地,我們認為起點1也是乙個「中轉點」)。顯而易見,如果我們想求出起點到乙個點的最短路徑,那我們必然要先求出中轉點的最短路徑(例如我們必須先求出點2 的最短路徑後,才能求出從起點到5的最短路徑)。

換句話說,如果起點1到某一點v0的最短路徑要經過中轉點vi,那麼中轉點vi一定是先於v0被確定了最短路徑的點。

我們把點分為兩類,一類是已確定最短路徑的點,稱為「白點」,另一類是未確定最短路徑的點,稱為「藍點」。如果我們要求出乙個點的最短路徑,就是把這個點由藍點變為白點。從起點到藍點的最短路徑上的中轉點在這個時刻只能是白點。

dijkstra的演算法思想,就是一開始將起點到起點的距離標記為0,而後進行n次迴圈,每次找出乙個到起點距離dis[u]最短的點u,將它從藍點變為白點。隨後列舉所有的藍點vi,如果以此白點為中轉到達藍點vi的路徑dis[u]+w[u][vi]更短的話,這將它作為vi的「更短路徑」dis[vi](此時還不確定是不是vi的最短路徑)。

就這樣,我們每找到乙個白點,就嘗試著用它修改其他所有的藍點。中轉點先於終點變成白點,故每乙個終點一定能夠被它的最後乙個中轉點所修改,而求得最短路徑。

簡稱ford(福特)演算法,同樣是用來計算從乙個點到其他所有點的最短路徑的演算法,也是一種單源最短路徑演算法。

能夠處理存在負邊權的情況,但無法處理存在負權迴路的情況(下文會有詳細說明)。

演算法時間複雜度:o(ne),n是頂點數,e是邊數。

演算法實現:

設s為起點,dis[v]即為s到v的最短距離,pre[v]為v前驅。w[j]是邊j的長度,且j連線u、v。

初始化:dis[s]=0,dis[v]=∞(v≠s),pre[s]=0

for (i = 1; i <= n-1; i++)

for (j = 1; j <= e; j++) //注意要列舉所有邊,不能列舉點。

if (dis[u]+w[j]演算法分析&思想講解:

bellman-ford演算法的思想很簡單。一開始認為起點是白點(dis[1]=0),每一次都列舉所有的邊,必然會有一些邊,連線著白點和藍點。因此每次都能用所有的白點去修改所有的藍點,每次迴圈也必然會有至少乙個藍點變成白點。

#include

#include

#include

#include

#include

using

namespace std;

int n,m,dx,dy;

double a[

110]

[110

],x[

110]

,y[110];

void

input()

scanf

("%d"

,&m)

;for

(i=0

;i)scanf

("%d%d"

,&dx,

&dy)

;return;}

void

floyed()

//計算最短路

intmain()

#include

#include

#include

#include

#include

using

namespace std;

int n,m,dx,dy;

double a[

110]

[110

],x[

110]

,y[110

],dis[

3010];

bool d[

3010];

void

input()

scanf

("%d"

,&m)

;for

(i=0

;i)scanf

("%d%d"

,&dx,

&dy)

;return;}

void

dij(

)//計算單源最短路

dis[dx]=0

; d[dx]=1

;for

(i=1

;i) d[w]=1

;for

(j=1

;j<=n;j++

)//鬆弛 if(

!d[j]

&&dis[w]

+a[w]

[j]) dis[j]

=dis[w]

+a[w]

[j];

}return;}

intmain()

#include

#include

#include

#include

#include

using

namespace std;

int n,m,dx,dy;

double x[

110]

,y[110

],dis[

110]

;struct jgt

b[10000];

void

input()

scanf

("%d"

,&m)

;for

(i=1

;i<=m;i++

)scanf

("%d%d"

,&dx,

&dy)

;return;}

void

ford()

//計算最短路

}return;}

intmain()

ssl1613最短路徑問題

description 平面上有n個點 n 100 每個點的座標均在 10000 10000之間。其中的一些點之間有連線。若有連線,則表示可從乙個點到達另乙個點,即兩點間有通路,通路的距離為兩點直線的距離。現在的任務是找出從一點到另一點之間的最短路徑。input 輸入檔案short.in,共有n m...

ssl1613 最短路徑問題

最短路徑問題 time limit 10000ms memory limit 65536k total submit 312 accepted 160 case time limit 1000ms description 平面上有n個點 n 100 每個點的座標均在 10000 10000之間。其中...

最短路徑問題 SSL 1613

平面上有n個點 n 100 每個點的座標均在 10000 10000之間。其中的一些點之間有連線。若有連線,則表示可從乙個點到達另乙個點,即兩點間有通路,通路的距離為兩點直線的距離。現在的任務是找出從一點到另一點之間的最短路徑。輸入檔案short.in,共有n m 3行,其中 第一行為乙個整數n。第...