題目描述:
給出乙個 n 個頂點 m 條邊的無向無權圖,頂點編號為 1 到 n。
問從頂點 1 開始,到其他每個點的最短路有幾條。
輸入格式
第一行包含 2 個正整數 n,m,為圖的頂點數與邊數。
接下來 m 行,每行兩個正整數 x,y,表示有一條頂點 x 連向頂點 y 的邊,請注意可能有自環與重邊。
輸出格式
輸出 n 行,每行乙個非負整數,第 i 行輸出從頂點 1 到頂點 i 有多少條不同的最短路,由於答案有可能會很大,你只需要輸出對 100003 取模後的結果即可。
如果無法到達頂點 i 則輸出 0。
資料範圍
1≤n≤10^5,
1≤m≤2×10^5
輸入樣例:
5 7
1 21 3
2 43 4
2 34 5
4 5
輸出樣例:
111
24
分析:
本題類似於揹包問題的方案數,如果是求起點到終點所有的路徑條數,直接遍歷圖的同時統計下方案數即可。現在要求的是最短路徑的條數,因此應該在計算最短路徑的過程中使用動態規劃的思想去求解。本題中涉及的邊都是無權邊,或者說邊權都是1,因此可以直接用bfs來求最短路徑。
回憶下基本的bfs過程:將起點加入佇列,訪問位置為true;當佇列非空時不斷取隊頭元素,將隊頭元素相鄰的訪問位為false的點都加入到佇列中來,同時更新這些點的最短路徑。這意味著如果從a擴充套件到b點時,將b入隊了,然後即使從c點擴充套件到b點,並且這兩種擴充套件的路徑中b的最短路徑都是相同的,但是由於b由a擴充套件了已經入隊了,再次由c擴充套件到時不會再次入隊了,而統計方案數則要統計所有的最短路徑情況。因此,設d[i]為目前起點到i點的最短路徑,cnt[i]是目前起點到i點最短路徑的條數,如果從上一點u向i點擴充套件,d[i] < d[u] + 1時,需要更新最短路徑長度,d[i] = d[u] + 1,並且此刻到i的最短路徑長度應該繼承到u的最短路徑條數,即cnt[i] = cnt[u];d[i] == d[u] + 1時,不需要更新最短路徑長度,但是需要將到u的最短路徑條數加到到i的最短路徑條數中,即cnt[i] += cnt[u]。
最短路徑長度和最短路徑條數更新的條件已經明確了,最後要明確的就是何時將節點加入到佇列中?從u擴充套件到i,但是d[u] + 1 > d[i],此時自然不用將i入隊;d[u] + 1 < d[i],這時候更新了i點的最短路徑長度,因此要將i入隊;那麼d[u] + 1 == d[i]時呢?此刻由於d[i]與d[u] + 1相等,必然已經經由其他點擴充套件過加入佇列了,而比d[i]更小的d[u]才剛剛出隊,d[i]必然還在佇列中,因此不用再次將i入隊了。這樣一來,標誌陣列st也就沒有必要設定了。
對於題目中的重邊和自環,重邊的存在有可能將最短路徑條數翻倍,自環的存在可以忽略,乙個點走一遍自環會使得到起點的距離加上1,必然不是最短距離。總的**如下:
#include #include #include using namespace std;
const int n = 100005,m = 400005,mod = 100003;
int n,m,idx,h[n],e[m],ne[m];
int d[n],cnt[n];
queueq;
void add(int a,int b)
void bfs()
else if(d[j] == d[u] + 1) cnt[j] = (cnt[j] + cnt[u]) % mod;}}
}int main()
bfs();
for(int i = 1;i <= n;i++) cout
}
最短路計數,次短路計數
acwing 1134.最短路計數 bfs 每個點只出隊一次,且入隊一次 dijkstra 每個點第一次出隊的序列一定滿足拓撲序 bellman ford spfa 出隊的時候都不一定是滿足最小,每個點可能出隊多次,有可能更新前面已經出隊的點,不具備拓撲序 但是要用 spfa 求最短路徑數,也是可以...
最短路計數
乙個無向圖上,沒有自環,所有邊的權值均為1,對於乙個點對 a,b 我們要把所有a與b之間所有最短路上的點的總個數輸出。總數 方程 if dis k map k,j dis j then inc dis k 所有最短路經過的點數之和 先求出floyd,然後 if dis i,k dis k,j dis...
最短路計數
題目描述 給出乙個nn個頂點mm條邊的無向無權圖,頂點編號為1 n1 n。問從頂點11開始,到其他每個點的最短路有幾條。輸入輸出格式 輸入格式 第一行包含22個正整數n,mn,m,為圖的頂點數與邊數。接下來mm行,每行22個正整數x,yx,y,表示有一條頂點xx連向頂點yy的邊,請注意可能有自環與重...