Перейти в: Мой блог
тема
ответ
Если вы хотите определить, может ли точка достичь конца, вы должны начать поиск с этой точки. Для определения всех точек требуется время. Поэтому рассмотрим обратную операцию, чтобы увидеть, к каким точкам можно получить доступ в обратном направлении от конечной точки. Постройте обратный график (поменяйте местами две конечные точки с каждой стороны), начните поиск с конечной точки, и точка, которая может быть достигнута, будет точкой, которая может достичь конечной точки.
Код
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int maxn=1e4+5;
const int maxm=2e5+5;
int n,m,c1,c2,s,t;
int h1[maxn],h2[maxn],d[maxn];
bool v[maxn],inq[maxn],can[maxn];
//这里的inq[]表示是否进入过队列,can[]表示是否可以作为最短路径上的点
struct edge{int to,nxt,w;}e1[maxm],e2[maxm];
inline void add1(int from,int to)
{
e1[++c1].to=to; e1[c1].nxt=h1[from]; h1[from]=c1;
}
inline void add2(int from,int to)
{
e2[++c2].to=to; e2[c2].nxt=h2[from]; h2[from]=c2;
}
queue<int> q1;
inline void bfs() //标记可以到达终点的点
{
q1.push(t); inq[t]=1;
while(q1.size())
{
int x=q1.front(); q1.pop();
for(int i=h2[x];i;i=e2[i].nxt)
{
int y=e2[i].to;
if(!inq[y]) inq[y]=1,q1.push(y);
}
}
}
inline void get_point() //标记可以位于路径上的点
{
for(int x=1;x<=n;x++)
{
can[x]=1;
for(int i=h1[x];i;i=e1[i].nxt)
{
int y=e1[i].to;
if(!inq[y]) {can[x]=0; break;}
}
}
}
priority_queue<pair<int,int> > q;
inline void dijkstra()
{
memset(d,0x3f,sizeof(d));
d[s]=0; q.push(make_pair(0,s));
while(q.size())
{
int x=q.top().second; q.pop();
if(v[x]) continue; v[x]=1;
for(int i=h1[x];i;i=e1[i].nxt)
{
int y=e1[i].to;
if(!can[y]) continue;
if(d[y]>d[x]+1)
{
d[y]=d[x]+1;
q.push(make_pair(-d[y],y));
}
}
}
}
inline void solve()
{
bfs(); get_point();
dijkstra();
if(d[t]==inf) printf("-1\n");
else printf("%d\n",d[t]);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int x,y; scanf("%d%d",&x,&y);
add1(x,y); add2(y,x);
}
scanf("%d%d",&s,&t);
solve();
return 0;
}