【2014】
D2T2 寻找道路
一道相较于代码能力更考验思维的题。
首先我们要意识到只跟终点有关的特殊性质,跑反向图是很常见的操作。
因此这道题我们就是先从终点跑一遍反向图,把能到达终点的点标记出来,因为最后路径上的点绝对是从这些点中选,注意特判如果起点跑不到终点就直接输出-1然后return 0。
接下来枚举这些能到达终点的点,先将它们都标记为路径上的点,再枚举它们的每一条边的终点,这些(当前枚举点对应的)终点有一个不能到达题目所给的终点,那么把已标记点去掉标记,表明它不能出现在路径上。
最后bfs跑一个最短路,只能跑被标记的点即可。
#include<bits/stdc++.h> #define ri register int #define ll long long #define For(i,l,r) for(ri i=l;i<=r;i++) #define Dfor(i,r,l) for(ri i=r;i>=l;i--) using namespace std; const int M=1e5+5; int dis[M],n,m,a,b,s,t; bool path[M],can[M]; vector<int>side[M]; vector<int>edis[M]; queue<int>q; inline ll read(){ ll f=1,sum=0; char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch)){sum=(sum<<1)+(sum<<3)+(ch^48);ch=getchar();} return f*sum; } int main(){ n=read(),m=read(); For(i,1,m){ a=read(),b=read(); side[a].push_back(b); edis[b].push_back(a); } s=read(),t=read(); can[t]=1;q.push(t); while(!q.empty()){ int u=q.front();q.pop(); for(int i=edis[u].size()-1;i>=0;i--){ int v=edis[u][i]; if(!can[v]){ can[v]=1; q.push(v); } } } if(!can[s]){printf("-1\n");return 0;} For(i,1,n){ if(can[i]){ path[i]=1; for(int j=side[i].size()-1;j>=0;j--){ int v=side[i][j]; if(!can[v]){ path[i]=0; break; } } } } if(!path[s]){printf("-1\n");return 0;} dis[s]=1;q.push(s); while(!q.empty()){ int u=q.front();q.pop(); if(u==t){printf("%d\n",dis[t]-1);return 0;} for(int i=side[u].size()-1;i>=0;i--){ int v=side[u][i]; if(path[v]&&!dis[v]){ dis[v]=dis[u]+1; q.push(v); } } } printf("-1\n"); return 0; }