题目描述
在有向图 GG 中,每条边的长度均为 11 ,现给定起点和终点,请你在图中找一条从起点到终点的路径,该路径满足以下条件:
- 路径上的所有点的出边所指向的点都直接或间接与终点连通。
- 在满足条件 11 的情况下使路径最短。
注意:图 GG 中可能存在重边和自环,题目保证终点没有出边。
请你输出符合条件的路径的长度。
输入输出格式
输入格式:
第一行有两个用一个空格隔开的整数 n 和 m ,表示图有 n 个点和 m 条边。
接下来的 mm 行每行 2 个整数 x,y ,之间用一个空格隔开,表示有一条边从点 x 指向点 y 。
最后一行有两个用一个空格隔开的整数 s,t ,表示起点为 s ,终点为 t 。
输出格式:
输出只有一行,包含一个整数,表示满足题目描述的最短路径的长度。如果这样的路径不存在,输出 −1 。
输入输出样例
说明
解释1:
如上图所示,箭头表示有向道路,圆点表示城市。起点 1 与终点 3 不连通,所以满足题目描述的路径不存在,故输出 −1 。
解释2:
如上图所示,满足条件的路径为 1 - > 3 - > 4 - > 5 。注意点 2 不能在答案路径中,因为点 2 连了一条边到点 6 ,而点 6 不与终点 5 连通。
【数据范围】
对于 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 。
列下此题要解决的问题
1.自环
2.如何判断一条路线上的点的所有出度都直接或间接的指向重点
1比较好解决,读入时加一句if(a==b)continue就好了,那如何解决2呢
从起点出发的话对于途径的每一个点都要判断是否可以直接/间接到终点,计算量太大,所以考虑反过来走,从终点出发,那么在此之前,连边时就要把所有的边反过来连,然后从终点出发往起点走
这样对不对呢,我们来证明一下
样例2原图
以样例2为例,反向连边后如上图,我们从5出发,可以走5->4->3->1,也可以走5->2->1,点6无论怎样都不会被走到,所以我们可以把点6从图中删除
但是这样的话2这个不合法点不就可以走了吗?所以我们在删除一个点时,还要删掉所有它能走到的点,因为它们也是不合法的
最后图中剩下的路径就是合法的了,对于一个合法的图求最短路,跑一边bfs即可,如果bfs的结果为0,说明走不到,输出-1即可
p.s还是从终点往起点走
完整代码
#include<bits/stdc++.h> using namespace std; const int MAXN=1e5+10; int n,m,x,y,qd,zd,ans[MAXN]; vector<int>g[MAXN]; queue<int>q; bool vis[MAXN],can[MAXN]; int main() { cin>>n>>m; for(int i=1;i<=m;i++) { cin>>x>>y; if(x==y)continue;//去自环 g[y].push_back(x); } cin>>qd>>zd; can[zd]=1;//从终点开始走 q.push(zd); while(!q.empty())//第一遍排除所有不合法的点,它们不会被标记 { int no=q.front();q.pop(); for(int i=0;i<g[no].size();i++) if(!can[g[no][i]]) can[g[no][i]]=1,q.push(g[no][i]); } memcpy(vis,can,sizeof(can));//复制一个同样的标记数组,因为在第一个标记数组中删除不合法点是有后效性的 for(int i=1;i<=n;i++)//把所有不合法点能走到的点全部删除 if(!can[i]) for(int j=0;j<g[i].size();j++) if(vis[g[i][j]]) vis[g[i][j]]=0; q.push(zd);//还是从终点开始走 while(!q.empty())//bfs { int no=q.front(); q.pop(); for(int i=0;i<g[no].size();i++) if(vis[g[no][i]]) { q.push(g[no][i]); vis[g[no][i]]=0; ans[g[no][i]]=ans[no]+1; } } if(ans[qd]==0)cout<<-1; else cout<<ans[qd];//快乐的输出 return 0; }
参考大佬@ _空_ 的题解