題目描述
在有向圖G 中,每條邊的長度均爲1 ,現給定起點和終點,請你在圖中找一條從起點到終點的路徑,該路徑滿足以下條件:
1 .路徑上的所有點的出邊所指向的點都直接或間接與終點連通。
2 .在滿足條件1 的情況下使路徑最短。
注意:圖G 中可能存在重邊和自環,題目保證終點沒有出邊。
請你輸出符合條件的路徑的長度。
輸入輸出格式
輸入格式:
輸入文件名爲road .in。
第一行有兩個用一個空格隔開的整數n 和m ,表示圖有n 個點和m 條邊。
接下來的m 行每行2 個整數x 、y ,之間用一個空格隔開,表示有一條邊從點x 指向點y 。
最後一行有兩個用一個空格隔開的整數s 、t ,表示起點爲s ,終點爲t 。
輸出格式:
輸出文件名爲road .out 。
輸出只有一行,包含一個整數,表示滿足題目᧿述的最短路徑的長度。如果這樣的路徑不存在,輸出- 1 。
輸入輸出樣例
說明
解釋1:
如上圖所示,箭頭表示有向道路,圓點表示城市。起點1 與終點3 不連通,所以滿足題
目᧿述的路徑不存在,故輸出- 1 。
解釋2:
如上圖所示,滿足條件的路徑爲1 - >3- >4- >5。注意點2 不能在答案路徑中,因爲點2連了一條邊到點6 ,而點6 不與終點5 連通。
對於30%的數據,0<n≤10,0<m≤20;
對於60%的數據,0<n≤100,0<m≤2000;
對於100%的數據,0<n≤10,000,0<m≤200,000,0<x,y,s,t≤n,x≠t。
思路:當我第一眼看這道題時,我原以爲D2T2肯定比較難,結果再看了看發現:WTF?這真的是D2T2難度??哎呀不說了,大水題一個。
想法很簡單,既然要判斷每個點與終點是否聯通,(以下爲我一本正經的口胡)我們可以考慮用並查集(這樣真的好嗎?),但是這是有向圖,那怎麼辦呢?我們發現,終點是不變的,而且只需判斷終點與其他點
的聯通性,那我們可以用一個技巧:把所有的邊都反向,然後從終點跑一遍BFS,遍歷全圖,這樣,沒有被訪問過的點就一定與終點不連通。爲什麼要用這種方法呢?因爲如果邊是正向,那麼我們定會讓每個點都跑
一遍BFS,無疑會TLE,考慮到從一個點出發能到達所有聯通的點,那麼我們可以反向BFS(實質是原來的起點與終點互換位置)。
處理完聯通性後,我們對所有的與終點不連通的點進行反向出邊遍歷(名詞是自己造的QAQ),對遍歷到的點標記爲不合法(因爲我們這條路要滿足條件1),這樣的話,再從起點s正向跑一遍SPFA,當遇到不合法的
點時就跳過,然後dist[ed]或-1就是最後的答案。(到達不了就是-1)。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<queue> using namespace std; const int N=10000+5; const int M=2e5+5; int read() { int ret=0,f=1; char c=getchar(); while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();} while(c>='0'&&c<='9') {ret=ret*10+c-'0';c=getchar();} return ret*f; } int n,m; struct edge{ int from,to; }e1[M],e2[M]; int head1[N],nxt1[M],tot1=0; int head2[N],nxt2[M],tot2=0; bool vis[N],np[N]; void adde(int f,int t) { e1[++tot1]=(edge){f,t}; e2[++tot2]=(edge){t,f}; nxt1[tot1]=head1[f]; nxt2[tot2]=head2[t]; head1[f]=tot1; head2[t]=tot2; } queue<int > q; int dist[N]; bool inq[N]; void bfs(int s) { vis[s]=1; q.push(s); while(!q.empty()) { int u=q.front(); q.pop(); for(int i=head2[u];i;i=nxt2[i]) { int v=e2[i].to; if(!vis[v]) q.push(v),vis[v]=1; } } } void solve() { for(int i=1;i<=n;i++) { if(!vis[i]) { for(int j=head2[i];j;j=nxt2[j]) { int v=e2[j].to; np[v]=1; } } } } void spfa(int s) { dist[s]=0; q.push(s); inq[s]=1; while(!q.empty()) { int u=q.front(); q.pop(); inq[u]=0; for(int i=head1[u];i;i=nxt1[i]) { int v=e1[i].to; if(np[v]) continue; if(dist[v]>dist[u]+1) { dist[v]=dist[u]+1; if(!inq[v]) { q.push(v); inq[v]=1; } } } } } int main() { memset(dist,0x3f,sizeof(dist)); n=read(),m=read(); int a,b; for(int i=1;i<=m;i++) { a=read(),b=read(); adde(a,b); } int st,ed; st=read(),ed=read(); bfs(ed); solve(); spfa(st); int ans=(dist[ed]>1e9?-1:dist[ed]); printf("%d\n",ans); return 0; }