题目描述
在有向图G中,每条边的长度均为1,现给定起点和终点,请你在图中找一条从起点到终点的路径,该路径满足以下条件:
1.路径上的所有点的出边所指向的点都直接或间接与终点连通。
2.在满足条件1的情况下使路径最短。
注意:图G中可能存在重边和自环,题目保证终点没有出边。
请你输出符合条件的路径的长度。
输入格式
第一行有两个用一个空格隔开的整数n和m,表示图有n个点和m条边。
接下来的m行每行2个整数x、y,之间用一个空格隔开,表示有一条边从点x指向点y。
最后一行有两个用一个空格隔开的整数s、t,表示起点为s,终点为t。
输出格式
输出只有一行,包含一个整数,表示满足题目描述的最短路径的长度。
如果这样的路径不存在,输出-1。
样例
输入样例
6 6
1 2
1 3
2 6
2 5
4 5
3 4
1 5
输出样例
3
算法1
(spfa) $O((m+n)logn)$
首先看一下题目,这个题目还是比较好懂的,就是给你一个图,然后给你一个起点和终点,让你找一下特殊最短路。
特殊点:这个最短路径上的点的所有出边都得间接或直接的指向终点。
好,明白了特殊点就可以来思考一下怎么去解决掉。
现在他给定一个t为终点,而且题目说明了,这个终点是没有出边的。那么久可以得到一个思路,这个路径上的点一定不指向除终点以外出度为0的点。
那么根据这个思路,我们就可以得到了一个做法,就是所有除终点以外出度为0的点直接相连的点都不能用。除去这些点以后,那么就剩下一个出度为0的点也就是终点,所以图中剩下的点一定是与终点直接或间接相连的。
操作完毕后直接spfa一下直接结束。
提醒:在操作时要建反图,还有记得判断无解。
C++ 代码
#include<bits/stdc++.h>
using namespace std;
int head[201000],ver[201000],ne[201000],edge[201000],tot=0;
int head1[201000],ver1[201000],ne1[201000],tot1=0;
int d[201000],v[201000];
int n,m;
int chu[201000];
int b[201000];
void add(int x,int y,int z)
{
ver[++tot]=y;
edge[tot]=z;
ne[tot]=head[x];
head[x]=tot;
}
void add1(int x,int y)
{
ver1[++tot1]=y;
ne1[tot1]=head1[x];
head1[x]=tot1;
}
void dfs(int x)
{
b[x]=1;
for(int i=head1[x];i;i=ne1[i])
{
int y=ver1[i];
b[y]=1;
}
}
queue<int>q;
void spfa(int s)
{
for(int i=1;i<=n;i++)
d[i]=1000000000;
d[s]=0;
v[s]=1;
q.push(s);
while(q.size())
{
int x=q.front();
q.pop();
v[x]=0;
for(int i=head[x];i;i=ne[i])
{
int y=ver[i],z=edge[i];
if(b[y])
{
v[y]=1;
continue;
}
else if(d[y]>d[x]+z)
{
d[y]=d[x]+z;
if(!v[y])
{
q.push(y);
v[y]=1;
}
}
}
}
}
int main()
{
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int x,y;
cin>>x>>y;
add(x,y,1);
add1(y,x);
chu[x]++;
}
int s,t;
cin>>s>>t;
for(int i=1;i<=n;i++)
{
if(!chu[i]&&i!=t)
{
dfs(i);
}
}
b[s]=0;spfa(s);
// for(int i=1;i<=n;i++)
// {
// cout<<b[i]<<' ';
// }
if(d[t]<1000000000)
cout<<d[t];
else
cout<<-1;
}