洛谷 P1613 跑路 倍增 最短路

2022-05-11 16:11:26 字數 1563 閱讀 1202

題目傳送門

大致題意:

給定一張\(n\)個結點\(m\)條邊的有向圖,邊權固定為1,每秒可以移動\(2^t\)(\(t\)為任意值)。求從\(1\)到\(n\)的最短所需時間。

其中\(n\leq 50,m\leq 10000,dis_\leq int_\)。

第一眼是個最短路,然後發現不對勁。

因為從\(1\)到\(n\)的最短路不一定是所求答案,即二進位制下\(1\)的個數不一定最少。

舉個栗子:

在這張圖中,很明顯最短路是\(1-2-4-7\),但需要\(2+1\)共\(2\)秒。而另一條路雖然長度為\(4\),但只需要一次\(2^2\)就可以到達,時間只需要\(1\)秒。

於是我們需要根據題目中\(2^t\)這個提示,考慮如何融入倍增的思想。

最終的演算法肯定還是落腳在最短路上,但是這個邊不應該是最初輸入進來的,而是通過我們的計算,可以一步到達的兩個點之間連邊。

什麼情況下兩個點可以一步到達?

對於\((u,v)\)是否能通過乙個\(2^t\)跨過去,我們如果能找到乙個\(k\)滿足\((u,k)\)能夠\(2^\)跨過去,並且,\((k,v)\)

也可以\(2^\)跨過去,那就一定可行。

於是考慮用\(dp[u][v][t]\)表示,從\(u\)到\(v\)是否能移動\(2^t\)到達。

對於輸入的邊\((u,v)\),當然是可以通過\(2^0\)距離到達的,那麼\(dp[u][v][0]=1\)。並連上\(u\)和\(v\)。

此外就如上所述,遍歷其他點\(k\),如果有dp[u][k][t-1]&dp[k][v][t-1]==1,那麼dp[u][v][t]=1,並且把\(u\),\(v\)連上。

完成了建邊之後,直接跑最短路即可。考慮到\(n\)的範圍只有\(50\),於是方便地選用\(floyd\)。

另外,\(t\)只需要列舉到\(31\)即可(\(int_=2^-1\))。

code:

#includeusing namespace std;

const int n=70;

int dis[n][n],dp[n][n][n];

int main()

for(int t=1;t<32;t++)

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

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

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

if(dp[u][k][t-1]&dp[k][v][t-1])

dis[u][v]=dp[u][v][t]=1;

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

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

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

dis[u][v]=min(dis[u][v],dis[u][k]+dis[k][v]);

printf("%d\n",dis[1][n]);

return 0;

}

洛谷 P1613 跑路(倍增 最短路)

小a的工作不僅繁瑣,更有苛刻的規定,要求小a每天早上在6 00之前到達公司,否則這個月工資清零。可是小a偏偏又有賴床的壞毛病。於是為了保住自己的工資,小a買了乙個十分牛b的空間跑路器,每秒鐘可以跑2 k千公尺 k是任意自然數 當然,這個機器是用longint存的,所以總跑路長度不能超過maxlong...

洛谷P1613 跑路 最短路 倍增

小a的工作不僅繁瑣,更有苛刻的規定,要求小a每天早上在6 00之前到達公司,否則這個月工資清零。可是小a偏偏又有賴床的壞毛病。於是為了保住自己的工資,小a買了乙個十分牛b的空間跑路器,每秒鐘可以跑2 k千公尺 k是任意自然數 當然,這個機器是用longint存的,所以總跑路長度不能超過maxlong...

洛谷 P1613 跑路(DP 倍增 最短路)

小a的工作不僅繁瑣,更有苛刻的規定,要求小a每天早上在6 00之前到達公司,否則這個月工資清零。可是小a偏偏又有賴床的壞毛病。於是為了保住自己的工資,小a買了乙個十分牛b的空間跑路器,每秒鐘可以跑2 k千公尺 k是任意自然數 當然,這個機器是用longint存的,所以總跑路長度不能超過maxlong...