Skip to main content

rust_algorithms/graph/
shortest_path.rs

1//! Eng qisqa yo'l algoritmlari: BFS, Dijkstra, Bellman-Ford, Floyd-Warshall.
2
3use super::Graph;
4use std::cmp::Reverse;
5use std::collections::{BinaryHeap, VecDeque};
6
7/// Og'irliksiz grafda eng qisqa yo'l — oddiy BFS.
8///
9/// Og'irliklar teng bo'lsa, Dijkstra ortiqcha: BFS **O(V+E)** da javob beradi.
10///
11/// Qaytadi: `start` dan `goal` gacha bo'lgan yo'l (tugunlar ro'yxati) yoki `None`.
12///
13/// # Misol
14/// ```
15/// use rust_algorithms::graph::{Graph, bfs_shortest_path};
16///
17/// let mut g = Graph::new_undirected(6);
18/// for (a, b) in [(0, 1), (1, 2), (2, 5), (0, 3), (3, 4), (4, 5)] {
19///     g.add_unweighted_edge(a, b);
20/// }
21/// let yol = bfs_shortest_path(&g, 0, 5).unwrap();
22/// assert_eq!(yol.len(), 4); // 0 → 1 → 2 → 5 (yoki 0 → 3 → 4 → 5)
23/// assert_eq!(yol[0], 0);
24/// assert_eq!(*yol.last().unwrap(), 5);
25/// ```
26pub fn bfs_shortest_path(g: &Graph, start: usize, goal: usize) -> Option<Vec<usize>> {
27    let n = g.node_count();
28    let mut ota: Vec<Option<usize>> = vec![None; n];
29    let mut korilgan = vec![false; n];
30    korilgan[start] = true;
31
32    let mut navbat = VecDeque::from([start]);
33    while let Some(u) = navbat.pop_front() {
34        if u == goal {
35            return Some(yolni_tikla(&ota, start, goal));
36        }
37        for e in g.neighbors(u) {
38            if !korilgan[e.to] {
39                korilgan[e.to] = true;
40                ota[e.to] = Some(u);
41                navbat.push_back(e.to);
42            }
43        }
44    }
45    if start == goal {
46        Some(vec![start])
47    } else {
48        None
49    }
50}
51
52/// **Dijkstra** — musbat og'irlikli grafda bitta manbadan barcha tugunlargacha
53/// eng qisqa masofalar.
54///
55/// **G'oya (ochko'zlik):** har qadamda "hali tekshirilmagan, lekin hozircha eng yaqin"
56/// tugunni olamiz va uning qo'shnilariga masofani yangilaymiz (relaxation).
57/// Musbat og'irliklarda bir marta olingan tugunning masofasi boshqa yaxshilanmaydi.
58///
59/// - **Time:** O((V + E) log V) — min-heap bilan. **Space:** O(V).
60/// - **Cheklov:** og'irliklar **manfiy bo'lmasligi** kerak
61///   (manfiy bo'lsa → [`bellman_ford`]).
62///
63/// Qaytadi: har bir tugun uchun masofa; yetib bo'lmasa `None`.
64///
65/// # Misol
66/// ```
67/// use rust_algorithms::graph::{Graph, dijkstra};
68///
69/// //  0 --4-- 1 --1-- 3
70/// //   \      |
71/// //    1     2
72/// //     \    |
73/// //      --- 2
74/// let mut g = Graph::new_undirected(4);
75/// g.add_edge(0, 1, 4);
76/// g.add_edge(0, 2, 1);
77/// g.add_edge(2, 1, 2);
78/// g.add_edge(1, 3, 1);
79///
80/// let d = dijkstra(&g, 0);
81/// assert_eq!(d[0], Some(0));
82/// assert_eq!(d[2], Some(1));
83/// assert_eq!(d[1], Some(3)); // 0→2→1 = 1+2 = 3, to'g'ridan-to'g'ri 4 dan arzon
84/// assert_eq!(d[3], Some(4));
85/// ```
86pub fn dijkstra(g: &Graph, start: usize) -> Vec<Option<i64>> {
87    let (masofa, _) = dijkstra_with_parents(g, start);
88    masofa
89}
90
91/// Dijkstra + yo'lni tiklash: `start` dan `goal` gacha `(narx, yo'l)`.
92///
93/// # Misol
94/// ```
95/// use rust_algorithms::graph::{Graph, dijkstra_path};
96///
97/// let mut g = Graph::new_undirected(4);
98/// g.add_edge(0, 1, 4);
99/// g.add_edge(0, 2, 1);
100/// g.add_edge(2, 1, 2);
101/// g.add_edge(1, 3, 1);
102///
103/// let (narx, yol) = dijkstra_path(&g, 0, 3).unwrap();
104/// assert_eq!(narx, 4);
105/// assert_eq!(yol, vec![0, 2, 1, 3]);
106/// ```
107pub fn dijkstra_path(g: &Graph, start: usize, goal: usize) -> Option<(i64, Vec<usize>)> {
108    let (masofa, ota) = dijkstra_with_parents(g, start);
109    let narx = masofa[goal]?;
110    Some((narx, yolni_tikla(&ota, start, goal)))
111}
112
113fn dijkstra_with_parents(g: &Graph, start: usize) -> (Vec<Option<i64>>, Vec<Option<usize>>) {
114    let n = g.node_count();
115    let mut masofa: Vec<Option<i64>> = vec![None; n];
116    let mut ota: Vec<Option<usize>> = vec![None; n];
117
118    // Rustning BinaryHeap — max-heap. Reverse bilan uni min-heapga aylantiramiz.
119    let mut heap = BinaryHeap::new();
120    masofa[start] = Some(0);
121    heap.push(Reverse((0i64, start)));
122
123    while let Some(Reverse((d, u))) = heap.pop() {
124        // Eskirgan yozuv (bir tugun heapga bir necha marta tushishi mumkin)
125        if masofa[u].is_some_and(|m| d > m) {
126            continue;
127        }
128        for e in g.neighbors(u) {
129            debug_assert!(e.weight >= 0, "Dijkstra manfiy og'irlik bilan ishlamaydi");
130            let yangi = d + e.weight;
131            if masofa[e.to].is_none_or(|m| yangi < m) {
132                masofa[e.to] = Some(yangi);
133                ota[e.to] = Some(u);
134                heap.push(Reverse((yangi, e.to)));
135            }
136        }
137    }
138    (masofa, ota)
139}
140
141/// **Bellman-Ford** — manfiy og'irliklar bilan ham ishlaydi va manfiy siklni aniqlaydi.
142///
143/// **G'oya:** har bir qirrani `V-1` marta "bo'shatamiz" (relax). Nima uchun `V-1`?
144/// Chunki siklsiz eng qisqa yo'lda ko'pi bilan `V-1` ta qirra bo'ladi.
145/// `V` -iteratsiyada ham yaxshilanish bo'lsa — demak **manfiy sikl** bor.
146///
147/// - **Time:** O(V · E), **Space:** O(V).
148/// - Manfiy sikl topilsa → `None`.
149///
150/// **Real qo'llanilishi:** valyuta arbitraji (manfiy sikl = foyda), tarmoq
151/// marshrutlash (RIP protokoli).
152///
153/// # Misol
154/// ```
155/// use rust_algorithms::graph::{Graph, bellman_ford};
156///
157/// let mut g = Graph::new_directed(4);
158/// g.add_edge(0, 1, 4);
159/// g.add_edge(0, 2, 5);
160/// g.add_edge(1, 3, 5);
161/// g.add_edge(2, 1, -3); // manfiy qirra — Dijkstra bu yerda xato qiladi
162///
163/// let d = bellman_ford(&g, 0).unwrap();
164/// assert_eq!(d[1], Some(2)); // 0→2→1 = 5 + (−3) = 2
165/// assert_eq!(d[3], Some(7));
166/// ```
167pub fn bellman_ford(g: &Graph, start: usize) -> Option<Vec<Option<i64>>> {
168    let n = g.node_count();
169    let mut masofa: Vec<Option<i64>> = vec![None; n];
170    masofa[start] = Some(0);
171
172    let qirralar: Vec<(usize, usize, i64)> = (0..n)
173        .flat_map(|u| g.neighbors(u).iter().map(move |e| (u, e.to, e.weight)))
174        .collect();
175
176    for _ in 0..n.saturating_sub(1) {
177        let mut ozgardi = false;
178        for &(u, v, w) in &qirralar {
179            if let Some(du) = masofa[u] {
180                if masofa[v].is_none_or(|dv| du + w < dv) {
181                    masofa[v] = Some(du + w);
182                    ozgardi = true;
183                }
184            }
185        }
186        if !ozgardi {
187            break; // erta to'xtash: hech narsa yaxshilanmadi
188        }
189    }
190
191    // Manfiy sikl tekshiruvi
192    for &(u, v, w) in &qirralar {
193        if let Some(du) = masofa[u] {
194            if masofa[v].is_none_or(|dv| du + w < dv) {
195                return None;
196            }
197        }
198    }
199    Some(masofa)
200}
201
202/// **Floyd-Warshall** — **barcha juftliklar** orasidagi eng qisqa masofalar.
203///
204/// **G'oya (dinamik dasturlash):** `k` ni 0 dan V-1 gacha yurgizib, "faqat
205/// `0..=k` tugunlaridan o'tishga ruxsat berilsa, i dan j gacha eng qisqa masofa
206/// qancha?" degan savolga javob beramiz. Uch qatorli tsikl — algoritmning butun mohiyati:
207///
208/// ```text
209/// d[i][j] = min(d[i][j], d[i][k] + d[k][j])
210/// ```
211///
212/// - **Time:** O(V³), **Space:** O(V²).
213/// - Kichik graflarda (V ≤ 500) juda qulay; manfiy qirralarga ruxsat (manfiy siklsiz).
214///
215/// # Misol
216/// ```
217/// use rust_algorithms::graph::{Graph, floyd_warshall};
218///
219/// let mut g = Graph::new_directed(3);
220/// g.add_edge(0, 1, 3);
221/// g.add_edge(1, 2, 4);
222/// g.add_edge(0, 2, 10);
223///
224/// let d = floyd_warshall(&g);
225/// assert_eq!(d[0][2], Some(7)); // 0→1→2 = 7 < 10
226/// assert_eq!(d[2][0], None);    // teskari yo'l yo'q
227/// assert_eq!(d[1][1], Some(0));
228/// ```
229pub fn floyd_warshall(g: &Graph) -> Vec<Vec<Option<i64>>> {
230    let n = g.node_count();
231    let mut d: Vec<Vec<Option<i64>>> = vec![vec![None; n]; n];
232
233    for (i, qator) in d.iter_mut().enumerate() {
234        qator[i] = Some(0);
235    }
236    for u in 0..n {
237        for e in g.neighbors(u) {
238            let hozirgi = d[u][e.to];
239            if hozirgi.is_none_or(|x| e.weight < x) {
240                d[u][e.to] = Some(e.weight);
241            }
242        }
243    }
244
245    for k in 0..n {
246        for i in 0..n {
247            let Some(dik) = d[i][k] else { continue };
248            for j in 0..n {
249                let Some(dkj) = d[k][j] else { continue };
250                if d[i][j].is_none_or(|dij| dik + dkj < dij) {
251                    d[i][j] = Some(dik + dkj);
252                }
253            }
254        }
255    }
256    d
257}
258
259/// `ota` massividan `start → goal` yo'lini tiklaydi.
260fn yolni_tikla(ota: &[Option<usize>], start: usize, goal: usize) -> Vec<usize> {
261    let mut yol = vec![goal];
262    let mut hozir = goal;
263    while hozir != start {
264        match ota[hozir] {
265            Some(p) => {
266                yol.push(p);
267                hozir = p;
268            }
269            None => break,
270        }
271    }
272    yol.reverse();
273    yol
274}
275
276#[cfg(test)]
277mod tests {
278    use super::*;
279
280    fn ogirlikli() -> Graph {
281        let mut g = Graph::new_undirected(6);
282        for (a, b, w) in [
283            (0, 1, 7),
284            (0, 2, 9),
285            (0, 5, 14),
286            (1, 2, 10),
287            (1, 3, 15),
288            (2, 3, 11),
289            (2, 5, 2),
290            (3, 4, 6),
291            (4, 5, 9),
292        ] {
293            g.add_edge(a, b, w);
294        }
295        g
296    }
297
298    #[test]
299    fn dijkstra_klassik_misol() {
300        // Wikipediadagi mashhur misol: 0 dan 4 gacha eng qisqa masofa 20
301        let g = ogirlikli();
302        let d = dijkstra(&g, 0);
303        assert_eq!(d[0], Some(0));
304        assert_eq!(d[1], Some(7));
305        assert_eq!(d[2], Some(9));
306        assert_eq!(d[3], Some(20));
307        assert_eq!(d[4], Some(20));
308        assert_eq!(d[5], Some(11));
309    }
310
311    #[test]
312    fn dijkstra_yolni_tiklaydi() {
313        let g = ogirlikli();
314        let (narx, yol) = dijkstra_path(&g, 0, 4).unwrap();
315        assert_eq!(narx, 20);
316        assert_eq!(yol.first(), Some(&0));
317        assert_eq!(yol.last(), Some(&4));
318        // yo'l bo'ylab og'irliklar yig'indisi narxga teng
319        let jami: i64 = yol
320            .windows(2)
321            .map(|w| {
322                g.neighbors(w[0])
323                    .iter()
324                    .filter(|e| e.to == w[1])
325                    .map(|e| e.weight)
326                    .min()
327                    .unwrap()
328            })
329            .sum();
330        assert_eq!(jami, narx);
331    }
332
333    #[test]
334    fn yetib_bolmaydigan_tugun() {
335        let mut g = Graph::new_undirected(3);
336        g.add_edge(0, 1, 5);
337        let d = dijkstra(&g, 0);
338        assert_eq!(d[2], None);
339        assert!(dijkstra_path(&g, 0, 2).is_none());
340    }
341
342    #[test]
343    fn bellman_ford_manfiy_qirralar() {
344        let mut g = Graph::new_directed(5);
345        for (a, b, w) in [
346            (0, 1, -1),
347            (0, 2, 4),
348            (1, 2, 3),
349            (1, 3, 2),
350            (1, 4, 2),
351            (3, 2, 5),
352            (3, 1, 1),
353            (4, 3, -3),
354        ] {
355            g.add_edge(a, b, w);
356        }
357        let d = bellman_ford(&g, 0).unwrap();
358        assert_eq!(d, vec![Some(0), Some(-1), Some(2), Some(-2), Some(1)]);
359    }
360
361    #[test]
362    fn manfiy_siklni_aniqlaydi() {
363        let mut g = Graph::new_directed(3);
364        g.add_edge(0, 1, 1);
365        g.add_edge(1, 2, -1);
366        g.add_edge(2, 1, -1); // 1 → 2 → 1 = -2
367        assert!(bellman_ford(&g, 0).is_none());
368    }
369
370    #[test]
371    fn floyd_dijkstra_bilan_mos() {
372        let g = ogirlikli();
373        let fw = floyd_warshall(&g);
374        for start in 0..g.node_count() {
375            assert_eq!(fw[start], dijkstra(&g, start));
376        }
377    }
378
379    #[test]
380    fn bfs_eng_kam_qadamli_yol() {
381        let mut g = Graph::new_undirected(7);
382        for (a, b) in [(0, 1), (1, 2), (2, 3), (3, 6), (0, 4), (4, 5), (5, 6)] {
383            g.add_unweighted_edge(a, b);
384        }
385        let yol = bfs_shortest_path(&g, 0, 6).unwrap();
386        assert_eq!(yol.len(), 4); // 0 → 4 → 5 → 6
387        assert_eq!(bfs_shortest_path(&g, 0, 0), Some(vec![0]));
388    }
389}