题目描述
在有向图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 ",ans); return 0; }