[luogu2296][寻找道路]
直接赋题目。。。。。
题目描述
在有向图G 中,每条边的长度均为1 ,现给定起点和终点,请你在图中找一条从起点到终点的路径,该路径满足以下条件:
1 .路径上的所有点的出边所指向的点都直接或间接与终点连通。
2 .在满足条件1 的情况下使路径最短。
注意:图G 中可能存在重边和自环,题目保证终点没有出边。
请你输出符合条件的路径的长度。
输入输出格式
输入格式:
输入文件名为road .in。
第一行有两个用一个空格隔开的整数n 和m ,表示图有n 个点和m 条边。
接下来的m 行每行2 个整数x 、y ,之间用一个空格隔开,表示有一条边从点x 指向点y 。
最后一行有两个用一个空格隔开的整数s 、t ,表示起点为s ,终点为t 。
输出格式:
输出文件名为road .out 。
输出只有一行,包含一个整数,表示满足题目᧿述的最短路径的长度。如果这样的路径不存在,输出- 1 。
输入输出样例
对于一般的这种没有权值的有向图,一般都会想到跑一边bfs,用一个数组记录花费(比如我)。
然而这道题的不同之处在于
1 .路径上的所有点的出边所指向的点都直接或间接与终点连通。
如图 按照题目中所述
2可以到达T,3也可以到达T,但是选择路径时可以选择3,不能选择2。
原因在于2有一个子节点为1,而1不能到达T,所以不能选择2。
清楚了这个之后,思路基本上就有了(因为我太弱,思路可能不太完美)
- 首先,存图时,存一个反图,便于后边从t开始的bfs
- 从t开始bfs一次,找出所有能到达t的点
- 讲不能到达t的父节点和此节点标记为不能走
- 最后,从s开始bfs一次,只走能走的点,并用一个数组记录路径长
最后附上代码
1 #include<cstdio> 2 #include<iostream> 3 #include<queue> 4 using namespace std; 5 queue<int>q1,q2; 6 struct node{ 7 int u,v,nxt; 8 }a[200010],b[200010]; 9 int n,m,head1[10010],head2[10010],vis1[10010],s,t,vis2[10010],vis3[10010]; 10 int main() 11 { 12 scanf("%d%d",&n,&m); 13 for(int i=1,x,y;i<=m;++i) 14 { 15 scanf("%d%d",&x,&y); 16 if(x!=y) 17 { 18 a[i].u=x,a[i].v=y,a[i].nxt=head1[x];//用a来存正向图 19 head1[x]=i; 20 b[i].u=y,b[i].v=x,b[i].nxt=head2[y];//b用来存反向图 21 head2[y]=i; 22 } 23 24 } 25 scanf("%d%d",&s,&t); 26 q2.push(t); 27 vis2[t]=1; 28 while(!q2.empty())//从t开始一遍bfs,用vis2记录所有能到达t的点(因为是反图嘛) 29 { 30 int qq=q2.front(); 31 q2.pop(); 32 for(int i=head2[qq];i;i=b[i].nxt) 33 { 34 int v=b[i].v; 35 if(!vis2[v]) 36 { 37 vis2[v]=1; 38 q2.push(v); 39 } 40 } 41 42 } 43 for(int i=1;i<=n;++i) 44 { 45 vis3[i]=1; 46 } 47 for(int i=1;i<=m;++i)//将不能到达的节点及其父节点变为不能到达, 48 { 49 if(!vis2[a[i].v]) vis3[a[i].u]=vis3[a[i].v]=0;//用vis3记录(不用vis2是为了防止后效性,即前面的赋值影响后面,导致vis2全变为0) 50 } 51 q1.push(s); 52 vis1[s]=1; 53 while(!q1.empty())//从s开始一遍bfs, 54 { 55 int qq=q1.front(); 56 q1.pop(); 57 for(int i=head1[qq];i;i=a[i].nxt) 58 { 59 int v=a[i].v; 60 if(v==t)//搜到了t就将其路径长输出 61 { 62 printf("%d",vis1[a[i].u]);//因为vis[3]初值为1,所以此处不用+1; 63 return 0; 64 } 65 else if(vis3[v]&&!vis1[v])//只走vis3中标记为能走的点(前边一大堆就是为了找这些点....) 66 { 67 vis1[v]=vis1[a[i].u]+1;//将每个节点的路径长变为其父节点 路径长+1,因为权值都是1,这也是能用bfs而可以不用dijkstra的原因 68 q1.push(v); 69 } 70 } 71 } 72 printf("-1");//如果不能到达就输出-1 73 return 0;//拜拜。。。。 74 }