题目描述 Description
在有向图G中,每条边的长度均为1,现给定起点和终点,请你在图中找一条从起点到终点的路径,该路径满足以下条件:
1.路径上的所有点的出边所指向的点都直接或间接与终点连通。
2.在满足条件1的情况下使路径最短。
注意:图G中可能存在重边和自环,题目保证终点没有出边。
请你输出符合条件的路径的长度。输入描述 Input Description
第一行有两个用一个空格隔开的整数n和m,表示图有n个点和m条边。
接下来的m行每行2个整数x、y,之间用一个空格隔开,表示有一条边从点x指向点y。
最后一行有两个用一个空格隔开的整数s、t,表示起点为s,终点为t。输出描述 Output Description
输出只有一行,包含一个整数,表示满足题目描述的最短路径的长度。如果这样的路径不存在,输出-1。样例 Sample
Input1
3 2
1 2
2 1
1 3
Output1
-1
Input2
6 6
1 2
1 3
2 6
2 5
4 5
3 4
1 5
Output2
3
数据范围及提示 Data Size & Hint
对于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。
题解:这个题的思想是先找到能走的点,然后跑最短路,由于边权都是1,所以可以用BFS来做。先反向建边跑一遍BFS,把能从终点到达的点标记出来,然后重新建边,从起点再跑一遍BFS找最短路。不要忘记把第一次BFS时用的数组清零。
PS:这题我偷懒想跑两遍spfa,然后。。。MDZZ
代码如下:
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int MAXE=200010;
const int MAXV=10010;
int first[MAXV],nxt[MAXE<<1],d[MAXV];
int x[MAXE<<1],y[MAXE<<1],a[MAXV];
bool used[MAXV];
int n,m,tot,s,t;
struct edge
{
int from,to;
}es[MAXE<<1];
void build(int f,int t)
{
es[++tot]=(edge){f,t};
nxt[tot]=first[f];
first[f]=tot;
}
void init1()//第一次bfs初始化
{
memset(first,-1,sizeof(first));
memset(used,0,sizeof(used));
tot=0;
}
void init2()//第二次bfs初始化
{
memset(first,-1,sizeof(first));
memset(es,0,sizeof(es));
memset(d,-1,sizeof(d));
memset(a,0,sizeof(a));
tot=0;
}
bool check(int ch)//检查一个点是否能走
{
for(int i=first[ch];i!=-1;i=nxt[i])
{
int v=es[i].to;
if(!used[v]) return false;
//只要这个点连着任何一个不与终点连通的点,这个点就不能用
}
return true;
}
void bfs1()//第一次bfs
{
int ww=1,tt=0;
a[1]=t;
used[t]=1;
while(ww>tt)
{
tt++;
for(int i=first[a[tt]];i!=-1;i=nxt[i])
{
int v=es[i].to;
if(!used[v])
{
ww++;
a[ww]=v;
used[v]=1;//标记一下能从终点到达的点
}
}
}
}
bool bfs2()
{
int ww=1,tt=0;
d[s]=0;
a[1]=s;
while(ww>tt)
{
tt++;
if(!check(a[tt])) continue;//如果当前点不能用直接continue
for(int i=first[a[tt]];i!=-1;i=nxt[i])
{
int v=es[i].to;
if(d[v]==-1)
{
d[v]=d[a[tt]]+1;
ww++;
a[ww]=v;
if(es[i].to==t)
{
printf("%d",d[v]);
return true;
}
}
}
}
return false;
}
int main()
{
scanf("%d%d",&n,&m);
init1();
for(int i=1;i<=m;i++)
{
scanf("%d%d",&x[i],&y[i]);
build(y[i],x[i]);//先反向建边
}
scanf("%d%d",&s,&t);
bfs1();
init2();
for(int i=1;i<=m;i++) build(x[i],y[i]);//正向建边,不要忘了初始化
if(!used[s])
{
printf("-1\n");
return 0;
}
if(!bfs2()) printf("-1\n");
return 0;
}
/*
6 6
1 2
1 3
2 5
2 6
3 4
4 5
1 5
*/