原题地址
https://www.luogu.org/problem/show?pid=2296
图论广搜最短路
解题思路
删点+反向bfs。反向建边建一个邻接表,枚举每个入度为0的点(终点除外),与该点直接相连的点都打上false标记。处理完之后从终点开始bfs(或者最短路也行),只走未被标记的点。
参考代码
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
int num=0;
int v[2000005],r[2000005];
bool vis[1000005],f[2000005];
struct mc
{
intx,y;
}a[2000005];
struct cm
{
intx,y,ne;
}e[2000005];
struct mn
{
intx,ans;
}p[2000005];
void put(int x,int y)
{
num++;
e[num].x=x;
e[num].y=y;
e[num].ne=v[x];
v[x]=num;
}
void clean(int x)
{
f[x]=1;
for(int i=v[x];i;i=e[i].ne)
f[e[i].y]=1;
}
int main()
{
ios::sync_with_stdio(false);
memset(f,0,sizeof(f));
memset(v,0,sizeof(v));
memset(vis,0,sizeof(vis));
memset(r,0,sizeof(r));
intn,m;
cin>>n>>m;
for(int i=1;i<=m;i++)
cin>>a[i].x>>a[i].y;
intsx=0,sy=0,rx;
for(int i=1;i<=m;i++)
{
if(a[i].x==sx&&a[i].y==sy) continue;
if(a[i].x==a[i].y) continue;
put(a[i].y,a[i].x);
r[a[i].x]++;
}
cin>>sx>>rx;
for(int i=1;i<=num;i++)
if(!r[i]&&i!=rx) clean(i);
int t=0,w=1;
p[1].x=rx,p[1].ans=0;
while(t<w)
{
t++;
intx=p[t].x;
for(int i=v[x];i;i=e[i].ne)
{
inty=e[i].y;
if(f[y]||vis[y]) continue;
w++;
p[w].x=y;
p[w].ans=p[t].ans+1;
if(y==sx)
{
cout<<p[w].ans;
return0;
}
}
}
cout<<-1;
return0;
}