我們知道在已知起點的情況下,求到其他任何一點的最短路是用dijkstra,那麼在乙個有向圖中,我們想知道任意兩點之間的最短路,我們就可以使用floyd,而且這個演算法表面看起來非常的簡單,就是乙個三重迴圈,如果這個圖有n個點,那麼複雜度為o(|n|3),**如下。
1for(int k=0;k)
2for(int i=0;i)
3for(int j=0;j)
4 d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
在複雜度這麼高的情況下,一般情況下如果不是板子題直接用的話肯定是會超時的,所以我們還是需要了解floyd是怎麼進行的,其實它的本質就是dp。
其實我從上面的**中不難看出floyd是採用狀態轉移的方式來更新各個點之間的距離的,而這個點就是k,即從i-j之間的最短路是否經過k點,不斷的更新從而取得最優解,下面我們詳細的說一下。
假設從頂點i出發,僅經由頂點vk=抵達頂點j的最短路徑成本為ak[i,j]。首先,a0[i,j]表示從i到j不經由其他任何頂點,所以其值就等於連線i,j邊的權值,如果不存在邊時其大小為正無窮,接下來是k=1,2,3,···,|n|的情況,我們需要通過ak-1來計算ak,那麼我們只需要考慮是否經過k點兩種情況。
如果經過k,則路徑會被分為i-k,k-j兩個路徑,而且這兩個路徑全都只經過vk-1,中的頂點,因此ak=ak-1[i,k]+ak-1[k,j]。
如果不經過k,那就意味著ak[i,j]只經過i,j及屬於vk-1中的頂點,所以ak[i,j]=ak-1[i,j];
綜上所知ak[i,j]=min(ak-1[i,j],ak-1[i,k]+ak-1[k,j])。
那麼我們接下來看這個題目
洛谷p1119災後重建
在這個題目中,圖的狀態是隨著時間而改變的,在不同的時刻的詢問下,任意兩點之間的最短路也會發生改變,如果每問一次就用一次floyd的話,毫無疑問的超時,那我們注意觀察題目可以發現,某乙個點能不能使用是隨著時間變化的,我們在前面提到過,floyd使用的點是根據k來變化的,及迴圈內部是用不到k+1及以後的點的,那麼因為它的詢問根據之間逐漸增加的,所以我們只要根據時間來不斷的從更新k內部的點即可。
下面是完整**
1 #include 2 #include 3 #include4 #include 5 #include 6 #include 7 #include 8 #include 9 #include
1011
using
namespace
std;
12#define ll long long
13static
const
int white=0;14
static
const
int gray=1;15
static
const
int black=2;16
static
const
int inf=(1
<<20
);17
intn,m,q;
18int time1[205
];19
int map[205][205
];20
void floyd(int
k)21
27int
main()
2838
for(int i=0;i<=n;i++)
39for(int j=0;j<=n;j++)
40 map[i][j]=((i==j)?0
:inf);
41for(int m=0;m)
4247 scanf("
%d",&q);
48for(int q=1;q<=q;q++)
4957
if(tinf)
58 printf("
-1\n");
59else
6063}64
return0;
65 }
Floyd 演算法 任意兩點間的最短路問題
求解所有兩點間的最短路的問題叫做任意兩點間的最短路問題。讓我們試著用dp來求解任意兩點間的最短路問題。只使用0 k的情況下,記i到j的最短路長度為d k 1 i j k 1時,認為只使用i和j,所以d 0 i j cost i j 接下來讓我們把只使用頂點0 k的問題歸納到只使用0 k 1的問題上。...
兩點間多條最短路徑
最短路徑的求法可能都知道,弗洛伊德和迪克斯特拉。這兩種方法都是求一條最短路徑,如果你想求多條最短路徑那就只能選擇其他方法了。網上已經有幾種演算法可以求多條最短路徑,最常見的就是刪邊法 迪克斯特拉。就是用狄克斯特拉求出一條最短路徑然後把最短路徑上的邊一條一條的刪除然後再求最短路徑。這個方法比較容易想但...
Dijstra求任意兩點間最短路徑並輸出
用迪傑斯特拉演算法求一點到其餘所有結點的最短路徑。先輸入乙個小於100的正整數n,然後輸入圖的鄰接矩陣 10000表示無窮大,即兩點之間沒有邊 最後輸入兩個0到n 1的整數表示兩個點。先用迪傑斯特拉演算法求給定的第乙個點到其餘所有結點的最短路徑。然後再輸出給定的兩個點之間的最短路徑 按順序輸出最短路...