程式設計思維 C TT 的美夢(SPFA演算法)

2021-10-04 20:27:32 字數 4083 閱讀 4645

這一晚,tt 做了個美夢!

在夢中,tt 的願望成真了,他成為了喵星的統領!喵星上有 n 個商業城市,編號 1 ~ n,其中 1 號城市是 tt 所在的城市,即首都。

喵星上共有 m 條有向道路供商業城市相互往來。但是隨著喵星商業的日漸繁榮,有些道路變得非常擁擠。正在 tt 為之苦惱之時,他的魔法小貓咪提出了乙個解決方案!tt 欣然接受並針對該方案頒布了一項新的政策。

具體政策如下:對每乙個商業城市標記乙個正整數,表示其繁榮程度,當每乙隻喵沿道路從乙個商業城市走到另乙個商業城市時,tt 都會收取它們(目的地繁榮程度 - 出發地繁榮程度)^ 3 的稅。

tt 打算測試一下這項政策是否合理,因此他想知道從首都出發,走到其他城市至少要交多少的稅,如果總金額小於 3 或者無法到達請悄咪咪地打出 『?』。

input

第一行輸入 t,表明共有 t 組資料。(1 <= t <= 50)

對於每一組資料,第一行輸入 n,表示點的個數。(1 <= n <= 200)

第二行輸入 n 個整數,表示 1 ~ n 點的權值 a[i]。(0 <= a[i] <= 20)

第三行輸入 m,表示有向道路的條數。(0 <= m <= 100000)

接下來 m 行,每行有兩個整數 a b,表示存在一條 a 到 b 的有向道路。

接下來給出乙個整數 q,表示詢問個數。(0 <= q <= 100000)

每一次詢問給出乙個 p,表示求 1 號點到 p 號點的最少稅費。

output

每個詢問輸出一行,如果不可達或稅費小於 3 則輸出 『?』。

sample input25

6 7 8 9 10

61 2

2 33 4

1 55 4

4 5245

101 2 4 4 5 6 7 8 9 10

101 2

2 33 1

1 44 5

5 66 7

7 88 9

9 10

23 10

sample output

case 1:34

case 2:??

一、spfa演算法

spfa演算法是一種改良的bellman-ford 演算法。

1.bellman-ford 演算法

前面學的floyd演算法和dijkstra演算法都有它的侷限性:

floyd演算法解決多源最短路徑問題,對於解決單源最短路徑問題顯得有些「浪費」。

dijkstra演算法無法解決存在負權邊的單源最短路徑問題。

而bellman-ford 演算法可以解決存在負權邊的單源最短路徑問題。

假設給定n個頂點、m條邊、源點為s,使用bellman-ford 演算法需要用到的2個一維陣列:

dis[i]:從點s到點i的最短距離

pre[i] = k:從點s到點i之前要經過點k

bellman-ford 演算法的主體:

//初始化

for(

int i =

1; i <= n; i++

)//bellman-ford演算法

dis[s]=0

;for

(int j =

1; j < n; j++)}

}

時間複雜度為o(nm)。

2.spfa演算法

spfa演算法是一種對bellman-ford 演算法進行改良的演算法。這個演算法增加了1個一維陣列和1個佇列:

佇列q:存放被成功鬆弛的點

inq[i] = 0/1:點i在/不在佇列q中

spfa演算法的主體:

//初始化

for(

int i =

1; i <= n; i++

)//spfa演算法

dis[s]=0

;q.push

(s);

inq[s]=1

;while

(!q.

empty()

)}}}

時間複雜度為o(km),k是乙個小於n 的常數,但是在特殊情況下k可能很大 。

3.改進的spfa演算法

雖然圖可以存在負權邊,但如果圖存在負權環路,則會陷入在負權環路中,無法找到最短路徑。

為了使演算法能夠判斷是否存在負權環路,在改進的spfa演算法中,增加了1個一維陣列:

cnt[i] = k:點i加入佇列後最短路徑有k條邊

當cnt[i] = n時,說明點i加入佇列後最短路徑有n條邊,但實際上最短路徑不應該有超過(n-1)條邊,故存在負權環路,無法找到最短路徑。

改進的spfa演算法的主體:

//初始化

for(

int i =

1; i <= n; i++

)//改進的spfa演算法

dis[s]=0

;inq[s]=1

;q.push

(s);

while

(!q.

empty()

) dis[v]

= dis[u]

+ w;

pre[v]

= u;if(

!inq[v])}

}}

二、解題

由題可知,圖可能存在負權邊和負權環路,故需要用到改進的spfa演算法。

同時,還需要對演算法作進一步地改進:

當cnt[i]=n時,說明點i及其所在的連通分量中的所有點都無法找到最短路徑(即不可達),則將這些點都標記起來,如果後面有詢問到這些點,則直接輸出「?」,以減少詢問的時間開銷。

進一步改進:

增加1個一維陣列:

visit[i] = false/true:點i可達/不可達

當cnt[i]=n時,使用dfs演算法,將點i及其所在的連通分量中的所有點的visit都標記為true。

#include

#include

#include

#include

#define inf 10000000

#define max_v 100000

#define max_e 100000

using

namespace std;

int t;

int n;

int a[max_v]

;int m;

int a, b;

int q, p;

struct node

edges[max_e]

;int head[max_v]

;int tot =0;

int dis[max_v]

;int inq[max_v]

;int cnt[max_v]

;bool visit[max_v]

;queue<

int> q;

void

add(

int u,

int v,

int w)

void

dfs(

int v)}}

void

spfa

(int s)

dis[s]=0

; inq[s]=1

; q.

push

(s);

while

(!q.

empty()

)if(!inq[v])}

}}}void

init()

intmain()

spfa(1

);scanf

("%d"

,&q)

;printf

("case %d:\n"

, t)

;for

(int i =

0; i < q; i++)}

}

程式設計思維與實踐 Week7 C TT的美夢

c tt的美夢 題目描述 這一晚,tt 做了個美夢!在夢中,tt 的願望成真了,他成為了喵星的統領!喵星上有 n 個商業城市,編號 1 n,其中 1 號城市是 tt 所在的城市,即首都。喵星上共有 m 條有向道路供商業城市相互往來。但是隨著喵星商業的日漸繁榮,有些道路變得非常擁擠。正在 tt 為之苦...

程式設計Week7 C TT的美夢

有n個城市,編號為1 n,每個城市有乙個繁榮程度,從城市a走到城市b,需要收取 b繁榮的 a繁榮度 3的稅,求從首都出發,到其他城市要交多少稅,若小於3或無法到達輸出 第一行輸入 t,表明共有 t 組資料。1 t 50 對於每一組資料,第一行輸入 n,表示點的個數。1 n 200 第二行輸入 n 個...

week7 作業C TT的美夢

這一晚,tt 做了個美夢!在夢中,tt 的願望成真了,他成為了喵星的統領!喵星上有 n 個商業城市,編號 1 n,其中 1 號城市是 tt 所在的城市,即首都。喵星上共有 m 條有向道路供商業城市相互往來。但是隨著喵星商業的日漸繁榮,有些道路變得非常擁擠。正在 tt 為之苦惱之時,他的魔法小貓咪提出...