1. 程式人生 > 實用技巧 >洛谷 P2296 尋找道路 題解

洛谷 P2296 尋找道路 題解

這道題具有很大的思維價值,所以我做了好多遍。

這道題與其他最短路問題最不一樣的地方就在於一個條件:路徑上的所有點的出邊所指向的點都直接或間接與終點連通。

那我們思考如何才能得出符合這個條件的點:

考慮這三個點集:1.所有的點 2.所有與終點連通的點 3.所有該點的出邊所指向的點都與終點連通的點

不難發現,第三個集合是符合條件的,而且我們知道如何從1篩到2(反向建邊+bfs),再從2篩到3(模擬判斷),那麼這道題我們就做完了。

注:因為邊權都為1,所以bfs即可計算單源最短路,並不需要dijkstra和SPFA

#include<iostream>
#include<cstdio>
#include
<cstring> #include<algorithm> #include<queue> #define int long long #define maxn 200010 #define rep(i,s,e) for(register int i=s;i<=e;++i) #define dwn(i,s,e) for(register int i=s;i>=e;--i) using namespace std; inline int read() { int x=0,f=1; char c=getchar(); while(c<'
0'||c>'9') {if(c=='-') f=-1; c=getchar();} while(c>='0'&&c<='9') {x=x*10+c-'0'; c=getchar();} return f*x; } inline void write(int x) { if(x<0){putchar('-');x=-x;} if(x>9)write(x/10); putchar(x%10+'0'); } int n,m,s,t; int cnt1,cnt2,flag; int head1[maxn],head2[maxn],book1[maxn],book2[maxn],mark[maxn];
struct node1 { int v,nex; }edge1[maxn]; struct node2 { int v,nex; }edge2[maxn]; inline void add1(int x,int y) { edge1[++cnt1].v=y; edge1[cnt1].nex=head1[x]; head1[x]=cnt1; } inline void add2(int x,int y) { edge2[++cnt2].v=y; edge2[cnt2].nex=head2[x]; head2[x]=cnt2; } void bfs_back(int st) { queue<int> q; q.push(st); book1[st]=1; while(!q.empty()) { int from=q.front(); q.pop(); for(int i=head1[from];i;i=edge1[i].nex) { int to=edge1[i].v; if(book1[to]==1) continue; book1[to]=1; q.push(to); } } } int bfs_front(int st) { queue<pair<int,int> > q; q.push(make_pair(st,0)); book2[st]=1; while(!q.empty()) { int from=q.front().first,step=q.front().second; q.pop(); if(from==t) { flag=1; return step; } for(int i=head2[from];i;i=edge2[i].nex) { int to=edge2[i].v; if(book2[to]==1||mark[to]==0) continue; book2[to]=1; q.push(make_pair(to,step+1)); } } if(flag==0) return -1; } signed main() { n=read();m=read(); rep(i,1,m) { int x=read(),y=read(); add1(y,x); add2(x,y); } s=read();t=read(); bfs_back(t); if(book1[s]==0) { write(-1); return 0; } rep(i,1,n) { if(book1[i]==1) { mark[i]=1; int from=i; for(int j=head2[from];j;j=edge2[j].nex) { int to=edge2[j].v; if(book1[to]==0) { mark[from]=0; break; } } } } int ans=bfs_front(s); write(ans); return 0; }