擴充套件Dijkstra

2022-05-13 10:02:03 字數 4113 閱讀 7684

本文從另乙個角度理解dijkstra演算法,可能會與通常dijkstra演算法的講解有一些區別。

最短路問題:給定有向圖$g = (v, e)$,每條邊形如$(x, y, w)$,其中$w$表示節點$x$至節點$y$的距離為$w \geq 0$。求節點$s$至節點$t$的最短路徑長度。

dijkstra演算法:令$f(x)$表示節點$x$至節點$t$的最短路徑長度。則

$$f(x) = \min_ f(y)+w,

$$邊界條件為$f(t) = 0$。

原理:我們可以通過迭代的方式計算出$f(x)$。初始狀態取$f(x) = \infty (x \neq t)$以及$f(t) = 0$。迭代停止的條件為一次迭代後所有$f(x)$的值未發生變化。在迭代$n = |v|$次之後必然收斂。於是,我們可以得到乙個$o(n(n+m))$的迭代演算法,其中$m = |e|$。

優化的方式就是用乙個堆模擬迭代。這個堆存放所有$f(y)$的值,每次取出最小的$f(y)$,那麼這個$f(y)$在今後的迭代中不再變化,從而由它影響到的節點$x$必須滿足$(x, y, w) \in e$,只需擴充套件$y$的所有反向邊即可。因為每個節點只會從堆中取出一次,從而至多$o(n+m)$個值會因擴充套件而插入堆中,故複雜度為$o((n+m)\log (n+m))$。

注:使用fibonacci堆可做到$o(m+n\log n)$。

codeforces 1407e. egor in the republic of dagestan

給定$n$個節點,$m$條邊的有向圖$g = (v, e)$,每條有向邊形如$(x, y, c)$其中$c \in \$。

要求給出乙個節點染色方案$a_1, a_2, \dots, a_n \in \$,使得對每個點$1 \leq x \leq n$,僅保留形如$(x, y, a_u)$的邊後,節點$1$至節點$n$的最短路最大。$n, m \leq 10^5$。

解法:令$f(x)$表示節點$x$至節點$n$的最短路的最大可能值。則

$$f(x) = \max_} \min_ f(y)+1,

$$邊界條件為$f(n) = 0$。

初始狀態為$f(x) = \infty (x \neq n)$以及$f(n) = 0$,迭代以上式子$n$次可收斂。從而得到乙個$o(n(n+m))$的演算法。

優化方式也是每次取出最小的$f(y)$來擴充套件即可,進而複雜度為$o((n+m)\log(n+m))$。由於這題邊權為$1$,只需佇列(bfs)而不需要堆即可取出最小值,故複雜度可做到$o(n+m)$。

kickstart 2020 round e. golden stone

給定$n$個節點,$m$條邊的無向圖$g = (v, e)$,一共有$s$種寶石,以及每個節點上擁有的寶石情況(擁有意味著無限資源)。

有$r$個打造方式,每個打造方式形如$(a_1, a_2, \dots, a_k) \to b$,其中$k \leq 3$,表示在同乙個節點若集齊寶石$a_1, a_2, \dots, a_k$各一顆,可將他們打造成寶石$b$。

你可以以$1$單位花費,將一顆寶石從乙個節點經過一條邊運送到另乙個節點。

求打造寶石$1$的最小花費。$n, m, s, r \leq 500$。

解法:令$f(x, c)$表示在節點$x$得到寶石$c$的最小花費。則

$$f(x, c) = \min \begin

f(y, c) + 1 & (x, y) \in e \\

\sum_^k f(x, a_i) & (a_1, a_2, \dots, a_k) \to b \land c \in \_^k

\end,

$$邊界條件為,$f(x, c) = 0$若節點$x$擁有寶石$c$。

初始狀態為若節點$x$擁有寶石$c$則$f(x, c) = 0$否則$f(x, c) = \infty$,迭代以上式子$ns$次可收斂。從而得到乙個$o((ns)^2(m+r))$的演算法。

優化方式每次取出最小的$f(y, c)$擴充套件即可,時間複雜度為$o((ns+ms+nr)\log(ns+ms+nr))$。

void solve()

auto has = arr>(n + 1);

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

auto to = arr>>>(s + 1);

for (int i = 1; i <= r; ++i)

); }

} const ll inf = 1000000000000ll;

auto f = arr(n + 1, s + 1);

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

for (int j = 1; j <= s; ++j)

f[i][j] = inf;

struct node

};priority_queueq;

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

); }

while (!q.empty())

); }

for (auto& e : to[cur.color]));}

} }ll res = inf;

for (int i = 1; i <= n; ++i) freshmin(res, f[i][1]);

if (res == inf) res = -1;

writeln(res);

}

codeforces 1387c. viruses

給你乙個上下文無關文法$g = (v, \sigma, r)$,其中

特別地,這個上下文無關文法不會產生空串,即$\epsilon \notin l(g)$。

同時給出$m$個字串$s_1, s_2, \dots, s_m \in \^+$。若字串$s$是$t$的子串,我們記作$s \models t$。

對$2 \leq s < n$,令$g_s = (v, \sigma, r, s)$表示$s$為初始符號的上下文無關文法,

約束:$|r| \leq 100, |s| = \sum_^m |s_i| \leq 50$。其中,乙個產生式$r$形如

$$r: a \to b_1 b_2 \dots b_k,$$

並記$|r| = k$。我們定義$|r| = \sum_ |r|$。

解法:首先,我們將上下文無關文法$g$化為chomsky正規化,即每個轉移$r$的長度$|r| \leq 2$。方法為,考慮轉移$r: a \to b_1 b_2 \dots b_k$,其中$k \geq 3$,我們定義

$$\begin

a & \to b_1 c_1, \\

c_1 & \to b_2 c_2, \\

c_2 & \to b_3 c_3, \\

\dots \\

c_ & \to b_ c_, \\

c_ & \to b_ b_k.

\end

$$這樣轉化後,轉移式的規模仍為$o(|r|)$。以下則直接假設$|r| \in \$。

接著,建立$m$個字串$s_1, s_2, \dots, s_m$的ac自動機,則該自動機的狀態集合為$\gamma$,$|\gamma| = o(|s|)$,並記$\downarrow$為其初始狀態,$\delta: \gamma \times \sigma \to \gamma$表示其轉移函式。令$f(s, x, y)$表示符號$s$所能產生的所有字串$l(g_s)$中的長度最小的字串$t$的長度,使得$\delta(x, t) = y$且不經過接受狀態。則我們要求$f(s, \downarrow, y)$,其中$y$不為接受狀態。我們有

$$f(s, x, y) = \min \begin

\min_u \,

$$邊界條件為對$a \in \$,$f(a, x, y) = 1$若$\delta(x, a) = y$且$x$與$y$均不為接受狀態。

狀態數一共$o(|r||s|^2)$個,每輪迭代複雜度為$o(|r||s|^3)$,從而總複雜度為$o(|r|^2|s|^5)$,是不可接受的。

但我們仍可用堆優化,每次取出最小的$f(s, x, y)$擴充套件即可,而每個狀態均攤擴充套件$o(|s|)$個新狀態,從而複雜度為$o(|r||s|^3 \log(|r||s|^3))$。

**:code

注:若限制堆中每個狀態至多有$1$個最優擴充套件,則堆中至多有$o(|r||s|^2)$個元素,複雜度可降為$o(|r||s|^3 \log(|r||s|^2))$。

資料結構課設 旅遊規劃(dijkstra擴充套件)

5 19 旅遊規劃 25分 有了一張自駕旅遊路線圖,你會知道城市間的高速公路長度 以及該公路要收取的過路費。現在需要你寫乙個程式,幫助前來諮詢的遊客找一條出發地和目的地之間的最短路徑。如果有若干條路徑都是最短的,那麼需要輸出最便宜的一條路徑。輸入說明 輸入資料的第1行給出4個正整數nn m m ss...

dijkstra和dijkstra堆優化模板

之前qaq一直沒有準備堆優化模板,本例以pat a1003為例,整理dijkstra和dijkstra堆優化模板 我們可以發現該篇幅找最小值部分是使用量乙個for迴圈 include include using namespace std int n,m,c1,c2 int edge 510 510...

(二)Dijkstra演算法

ifndef dijkstra define dijkstra include using namespace std void testdijstra const int max node 1000 最簡單的 用二維陣列來記錄graph和weight 斐波那契堆實現 insert,get 1.最普...