题目描述
在有向图 G 中,每条边的长度均为 1,现给定起点和终点,请你在图中找一条从起点到 终点的路径,该路径满足以下条件:
- 路径上的所有点的出边所指向的点都直接或间接与终点连通。
- 在满足条件 1 的情况下使路径最短。
注意:图 G 中可能存在重边和自环,题目保证终点没有出边。 请你输出符合条件的路径的长度。
输入
第一行有两个用一个空格隔开的整数 n 和 m,表示图有 n 个点和 m 条边。
接下来的 m 行每行 2 个整数 x、y,之间用一个空格隔开,表示有一条边从点 x 指向点y。
最后一行有两个用一个空格隔开的整数 s、t,表示起点为 s,终点为 t。
输出
输出只有一行,包含一个整数,表示满足题目描述的最短路径的长度。
如果这样的路径不存在,输出-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
对于 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。
题解
考虑当前结点u能不能走,遍历u的所有出边连向v,如果有一个v不与终点直接或间接连通,那么u就不能走。
所以我们想要知道图中任意一点与终点的连通情况。观察数据:60%的点可以用floyd,100%的点我们就只能用spfa。首先反向建图,从终点做一遍spfa,如果终点到某个点的最短路等于inf,那么他们不连通。
然后正向建图。预处理出n个点哪些可以走哪些不能走,再从起点做一边spfa,只经过可以走的点,算出最短路就ok。
#include<cmath> #include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define ll long long const int maxn=10000+50; const int maxm=200000+50; const int maxx=2139062143; int n,m,x[maxm],y[maxm],s,t; int fir[maxn],to[maxm],nex[maxm],wi[maxm],ecnt; int c[maxn],q[2000001]; bool p[maxn],dis[maxn][maxn],u[maxn]; template<typename T>void read(T& aa){ char cc; ll ff;aa=0;cc=getchar();ff=1; while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); aa*=ff; } void add_edge(int u,int v){ nex[++ecnt]=fir[u];fir[u]=ecnt;to[ecnt]=v;wi[ecnt]=1; } void spfa(int x){ int head=0,tail=1; memset(p,false,sizeof(p)); memset(c,127,sizeof(c)); p[x]=true; c[x]=0; q[1]=x; while(head<tail){ head++; int u=q[head]; p[u]=false; for(int e=fir[u];e;e=nex[e]){ int v=to[e]; if(c[u]+wi[e]<c[v]){ c[v]=c[u]+wi[e]; if(!p[v]){ tail++; p[v]=true; q[tail]=v; } } } } } void spfa1(int x){ int head=0,tail=1; memset(p,false,sizeof(p)); memset(c,127,sizeof(c)); p[x]=true; c[x]=0; q[1]=x; while(head<tail){ head++; int uu=q[head]; p[uu]=false; for(int e=fir[uu];e;e=nex[e]){ int v=to[e]; if(u[v]&&c[uu]+wi[e]<c[v]){ c[v]=c[uu]+wi[e]; if(!p[v]){ tail++; p[v]=true; q[tail]=v; } } } } } int main(){ memset(dis,false,sizeof(dis)); memset(u,true,sizeof(u)); read(n),read(m); for(int i=1;i<=m;i++){ read(x[i]),read(y[i]); add_edge(y[i],x[i]); } read(s),read(t); spfa(t); for(int i=1;i<=n;i++) if(c[i]<maxx) dis[i][t]=true; memset(fir,0,sizeof(fir)); memset(to,0,sizeof(to)); memset(wi,0,sizeof(wi)); memset(nex,0,sizeof(nex));ecnt=0; for(int i=1;i<=m;i++) add_edge(x[i],y[i]); for(int i=1;i<=n;i++) if(i!=t){ for(int e=fir[i];e;e=nex[e]){ int v=to[e]; if(!dis[v][t]){ u[i]=false; break; } } } if(!u[s]){ cout<<"-1"<<endl; return 0; } spfa1(s); if(c[t]==maxx) cout<<"-1"<<endl; else cout<<c[t]<<endl; return 0; }