[Question Solution] Find the way

Source of the subject: Luo Gu

Title description

In the directed graph G, the length of each side is 1. Now given the start and end points, please find a path from the start point to the end point in the graph. The path meets the following conditions:

1. The points pointed to by the out edges of all points on the path are directly or indirectly connected to the end point.
2. Make the path the shortest if condition 1 is met.
Note: There may be multiple edges and self-loops in graph G, and the problem should ensure that there is no edge out of the end point.

Please output the length of the qualified path.

Input format

The first line has two integers n and m separated by a space, which means that the graph has n points and m edges.

The next m lines have 2 integers x, y in each line, separated by a space, indicating that there is an edge from point x to point y.

There are two integers s, t separated by a space in the last line, indicating that the start point is s and the end point is t.

Output format

The output is only one line, containing an integer, indicating the length of the shortest path that satisfies the description of the title. If such a path does not exist, output −1.

Input example 1

3 2
1 2
2 1
1 3

Sample output 1

-1

Input example 2

6 6
1 2
1 3
2 6
2 5
4 5
3 4
1 5

Sample output 2

3
Instructions/Prompts
Explanation 1:
Insert picture description here

As shown in the figure above, arrows indicate directed roads, and dots indicate cities. The starting point 1 1 and the ending point 3 3 are not connected, so the path that meets the problem description does not exist, so output -1−1.

Explanation 2:
Insert picture description here

As shown in the figure above, the path that meets the conditions is 1->3->4->5. Note that point 2 cannot be in the answer path, because point 2 connects an edge to point 6, and point 6 is not connected to end point 5.

【data range】

For 30% of the data, 0 <n≤10, 0 <m≤20;

For 60% of the data, 0 <n≤100, 0 <m<m≤2000;

For 100% data, 0<n≤10000, 0<m≤200000, 0<x,y,s,t≤n,x,s≠t.

Ideas:

Reference to this problem solutions
have to do is:
1, the reverse side of all, from the end ed start bfs, marking the end ed start point may come

2. Enumerate each point. If the point is not marked, then enumerate each of its outgoing edges (reversed). If the point it points to is marked, it means that the marked point is illegal. Delete ,
Note that it is better to have a second array mark. Deleting a point in an array has aftereffect type. If a point starts to be marked, it is deleted through a point with a smaller serial number, then when it is accessed It will be regarded as a point that was not marked at the beginning, and legal points will be deleted through it.
The above is from _kong_'s blog

3. Take the shortest path from a single source point on a legal point

code: (a bit long, but the idea is clear)

#include<bits/stdc++.h>
using namespace std;
const int N=1e4+10;
int n,m,st,ed,vis[N],vis1[N],dis[N],x[N],y[N];
vector <int> a[N],b[N];
queue <int> q;
void bfs(int s) //反向标记 
{
    
    
	q.push(s);
	while (!q.empty())
	{
    
    
		int t=q.front();
		q.pop();
		vis[t]=1;
		for (int i=0;i<b[t].size();i++)
		{
    
    
			int to=b[t][i];
			if (vis[to]==0)
			{
    
    
				q.push(to);
				vis[to]=1;
			}
		}
	}
}

void cancel()
{
    
    
	memcpy(vis1,vis,sizeof(vis));
	for (int i=1;i<=n;i++)
	  if (vis[i]==0)
	  {
    
    
          for (int j=0;j<b[i].size();j++) 
	        vis1[b[i][j]]=0;
	  }
	for (int i=1;i<=n;i++)
	{
    
    
	    if (vis1[i]==0)
		{
    
    
		    for (int j=0;j<a[i].size();j++)
			  a[i][j]=0;	
		}	
	} 
}

void init()
{
    
    
	scanf("%d%d",&n,&m);
	for (int i=1;i<=m;i++)
	{
    
    
		int x,y;
		scanf("%d%d",&x,&y);
		if (x==y) continue;
		a[x].push_back(y);//正向边 
		b[y].push_back(x);//反向边 
	}
	scanf("%d%d",&st,&ed);
}

void spfa(int s)
{
    
    
	while (!q.empty()) q.pop();
	for (int i=1;i<=n;i++) dis[i]=99999999,vis[i]=0;
	dis[s]=0;
	q.push(s);
	vis[s]=1;
	while (!q.empty())
	{
    
    
		int t=q.front();
		q.pop();
		vis[t]=1;
		for (int i=0;i<a[t].size();i++)
		{
    
    
			int to=a[t][i];
			if (dis[to]>dis[t]+1)
			{
    
    
				dis[to]=dis[t]+1;
				if (vis[to]==0)
				{
    
    
					q.push(to);
					vis[to]=1;
				}
			}
		}
	}
}
int main()
{
    
    
	init();
	bfs(ed); //从终点反向标记 	

    if (vis[ed]==0)  //起点无法到达终点就直接结束程序 
    {
    
    
    	cout<<-1<<endl;
    	return 0;
	}

	cancel();//撤去不符合条件的点	
	
	spfa(st);//单元点最短路 
	if (dis[ed]==99999999) cout<<-1<<endl;
	else cout<<dis[ed]<<endl;
	return 0;
}

Guess you like

Origin blog.csdn.net/weixin_45485187/article/details/102750099