https://www.luogu.org/problemnew/show/P2038
题目描述
在有向图 GG 中,每条边的长度均为 11,现给定起点和终点,请你在图中找一条从起点到终点的路径,该路径满足以下条件:
- 路径上的所有点的出边所指向的点都直接或间接与终点连通。
- 在满足条件11的情况下使路径最短。
注意:图 GG 中可能存在重边和自环,题目保证终点没有出边。
请你输出符合条件的路径的长度。
输入输出格式
输入格式:
第一行有两个用一个空格隔开的整数 nn 和 mm,表示图有 nn 个点和 mm 条边。
接下来的 mm 行每行 22 个整数 x,yx,y,之间用一个空格隔开,表示有一条边从点 xx 指向点yy。
最后一行有两个用一个空格隔开的整数 s, ts,t,表示起点为 ss,终点为 tt。
输出格式:
输出只有一行,包含一个整数,表示满足题目描述的最短路径的长度。如果这样的路径不存在,输出-1−1。
输入输出样例
输入样例#1: 复制
3 2 1 2 2 1 1 3
输出样例#1: 复制
-1
输入样例#2: 复制
6 6 1 2 1 3 2 6 2 5 4 5 3 4 1 5
输出样例#2: 复制
3
说明
解释1:
如上图所示,箭头表示有向道路,圆点表示城市。起点11与终点33不连通,所以满足题目描述的路径不存在,故输出-1−1 。
解释2:
如上图所示,满足条件的路径为11- >33- >44- >55。注意点22 不能在答案路径中,因为点22连了一条边到点66 ,而点66 不与终点55 连通。
【数据范围】
对于30\%30%的数据,0 < n \le 100<n≤10,0 < m \le 200<m≤20;
对于60\%60%的数据,0 < n \le 1000<n≤100,0 < m \le 20000<m≤2000;
对于100\%100%的数据,0 < n \le 10000, 0 < m \le 200000,0 < x,y,s,t \le n, x,s \ne t0<n≤10000,0<m≤200000,0<x,y,s,t≤n,x,s≠t。
反向建边,从终点bfs一遍,选出所有可以的节点
再跑一遍bfs,O(m),优秀
#include<cstdio>
using namespace std;
int read()
{
int ret=0; char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9')
ret=(ret<<1)+(ret<<3)+ch-'0',
ch=getchar();
return ret;
}
const int N=1e6+5;
int n,m,s,g,l,r,q[N],du[N],w[N];
bool fl[N],bj[N];
int cnt,to[N],nxt[N],he[N];
struct NA{
int u,v;
}e[N];
inline void add(int u,int v)
{
to[++cnt]=v;
nxt[cnt]=he[u];
he[u]=cnt;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int u=read(),v=read();
if(u!=v)
{
e[i].u=u,e[i].v=v,
add(v,u),du[u]++;
}
}
s=read(),g=read();
l=r=1,q[1]=g,fl[g]=1,bj[g]=1;;
while(l<=r)
{
int u=q[l];
for(int e=he[u];e;e=nxt[e])
{
int v=to[e];
if(!fl[v]) fl[v]=1,q[++r]=v,du[v]--;
else if(fl[v]) du[v]--;
if(!du[v]) bj[v]=1;
}
l++;
}
if(!bj[s])
{
puts("-1");
fclose(stdin); fclose(stdout);
return 0;
}
cnt=0;
for(int i=1;i<=n;i++) he[i]=fl[i]=0;
for(int i=1;i<=m;i++)
if(e[i].u&&e[i].v&&bj[e[i].v]&&bj[e[i].u])
add(e[i].u,e[i].v);
l=r=1,q[1]=s,fl[s]=1;
while(l<=r)
{
int u=q[l];
if(u==g) break;
for(int e=he[u];e;e=nxt[e])
{
int v=to[e];
if(!fl[v]&&bj[v])
fl[v]=1,q[++r]=v,w[v]=w[u]+1;
}
l++;
}
if(!w[g]&&s!=g) puts("-1");
else printf("%d\n",w[g]);
return 0;
}