潛入蘇拉瑪(BFS 構造)

2022-05-21 15:03:08 字數 1891 閱讀 3846

時間限制: 1 sec 記憶體限制: 128 mb

你接到了⼀個任務,讓你潛⼊蘇拉瑪城,和線⼈取得聯絡。蘇拉瑪的地圖是⼀張n個點m條邊的⽆向圖,每個點表⽰蘇拉瑪城的⼀個路⼜,每條邊表⽰蘇拉瑪內的⼀條道路,長度都是1。你從s號節點出發,線⼈在t號節點。

由於蘇拉瑪城內都是夜之⼦的哨兵,你需要假⾯偽裝才能在蘇拉瑪的道路上⾏⾛。你的偽裝只能堅持你⾛完k段道路不被發現,幸好在蘇拉瑪城內還有p個內應(分別在節點ai上),他們可以修復你的偽裝,讓它恢復到剛開始的狀態。

你想知道k⾄少需要是多少,才能讓你成功找到線⼈。

第⼀⾏⼀個正整數cas表⽰測試資料組數。

每組測試資料第⼀⾏有三個數n,m,p如上⽂所述,第⼆⾏p個數表⽰內應的位置。接下來m⾏,每⾏2個數表⽰⼀條邊。最後⼀⾏s和t表⽰你開始的節點和你的⽬標節點。

對於每組資料:如果你⽆法到達線⼈那⾥,輸出-1,否則輸出最⼩的k。

2

6 6 3

1 3 6

1 22 3

4 25 6

4 53 4

1 67 10 3

1 3 4

1 24 2

7 54 5

7 12 5

7 23 7

3 25 1

4 6

3

-1

對於100%的資料,1≤k,s,t≤n≤100000,1≤m≤150000,1≤cas≤5。

把起點、終點、內應都視為原點。

假設答案一定是偶數,也就是從\(s\)到\(t\)經過兩個相鄰原點的距離都\(\le 2k\)。

這樣問題就轉化為從每個原點出發\(bfs\) 各走\(k\)步,走出的點集是\(s,t\)聯通。

如果\(s=t,ans=0\)。否則,

每次將相鄰的點加入,重新\(bfs\),相當於\(ans+=2\)。

但是答案顯然有奇數的情況,我們只需在每條邊中間加一條中間點,也就是說如果\(i-j\)有一條邊,改為\(i-x,x-j\)個有一條邊。這樣就保證了結果一定是偶數,最後把答案\(\div 2\)即可。

注意到是無向圖,判連通性可以用並查集,加上線性的遍歷,最終複雜度就是\(o(nlogn)\)。

//#pragma gcc optimize(2)

//#pragma gcc optimize(3, "ofast", "inline")

#include "bits/stdc++.h"

using namespace std;

typedef long long ll;

typedef unsigned long long ull;

typedef pairpii;

const int n=1e6+5;

const ll mod=1e9+7;

const double eps=1e-5;

//const double pi=acos(-1);

vectorg[n];

int vis[n],f[n];

int getf(int x)

int main()

k=n+1;

while(m--)

int x,y;

cin>>x>>y;

if(!vis[x]) q.push(x),vis[x]=1;

if(!vis[y]) q.push(y),vis[y]=1;

int ans=0;

while(1)

while(!q.empty())

}if(getf(x)==getf(y))

break;

while(!p.empty())

}cout<}

return 0;

}