题目描述

在有向图 GGG 中,每条边的长度均为 111,现给定起点和终点,请你在图中找一条从起点到终点的路径,该路径满足以下条件:

  1. 路径上的所有点的出边所指向的点都直接或间接与终点连通。
  2. 在满足条件1 1 1的情况下使路径最短。

注意:图 GGG 中可能存在重边和自环,题目保证终点没有出边。

请你输出符合条件的路径的长度。

输入输出格式

输入格式:

第一行有两个用一个空格隔开的整数 nnnmmm,表示图有 nnn 个点和 mmm 条边。

接下来的 mmm 行每行 222 个整数 x,yx,yx,y,之间用一个空格隔开,表示有一条边从点 xxx 指向点yyy

最后一行有两个用一个空格隔开的整数 s,ts, ts,t,表示起点为 sss,终点为 ttt

输出格式:

输出只有一行,包含一个整数,表示满足题目描述的最短路径的长度。如果这样的路径不存在,输出−1-11

输入输出样例

输入样例#1: 复制
3 2  
1 2  
2 1  
1 3  
输出样例#1: 复制
-1
输入样例#2: 复制
6 6  
1 2  
1 3  
2 6  
2 5  
4 5  
3 4  
1 5  
输出样例#2: 复制
3

说明

解释1:

如上图所示,箭头表示有向道路,圆点表示城市。起点11 1与终点33 3不连通,所以满足题目描述的路径不存在,故输出−1-11

解释2:

如上图所示,满足条件的路径为11 1- >333- >444- >555。注意点222 不能在答案路径中,因为点222连了一条边到点666 ,而点666 不与终点555 连通。

【数据范围】

对于30%30\%30%的数据,0<n≤100 < n \le 100<n100<m≤200 < m \le 200<m20;

对于60%60\%60%的数据,0<n≤1000 < n \le 1000<n1000<m≤20000 < m \le 20000<m2000;

对于100%100\%100%的数据,0<n≤10000,0<m≤200000,0<x,y,s,t≤n,x,s≠t0 < n \le 10000, 0 < m \le 200000,0 < x,y,s,t \le n, x,s \ne t0<n10000,0<m200000,0<x,y,s,tn,x,st


思路是很好想的我感觉

  • 找出所有不能到达终点的点
  • 将出边是不能到达终点的点的点删掉
  • 加入没有删掉的点
  • 跑最短路

值得一提的是:
将出边是不能到达终点的点的点删掉,我用了一个数组fa(字面意思),然而由于做树的题目太多了忘记了一个点可以有多个入点

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
#include <vector>
#define maxn 410000
using namespace std ;
int read() {
	int x = 0 , f = 1 ; char s = getchar() ;
	while(s > '9' || s < '0') {if(s == '-') f = -1 ; s = getchar() ;}
	while(s <='9' && s >='0') {x = x * 10 + (s-'0'); s = getchar() ;}
	return x*f ;
}
int n , m ;
typedef pair<int,int>pa ;
struct dy {
	int x , y , z , next ;
}b[maxn] , a[maxn] ; 
int t , head[maxn] , vis[maxn] , dis[maxn] , s , st  , book[maxn] ;
vector<int>fa[11000] ;
priority_queue<pa ,vector<pa> , greater<pa> > q ;
inline void Add(int x ,int y) {
	b[++t].x = x ;
	b[t].y = y ;
	b[t].next = head[x] ;
	head[x] = t;
} 
void add(int x,int y) {
	a[++t].x = x ;
	a[t].y = y ;
	a[t].z = 1 ;
	a[t].next = head[x] ;
	head[x] = t ;
}
void dfs(int x) {
	if(vis[x]) return ;
	vis[x] = 1 ;
	for(int i = head[x] ; i ; i = b[i].next) {
		int v = b[i].y ;
		if(!vis[v]) {
			dfs(v) ;
		}
	}
}
void dij(int s) {
	memset(vis,0,sizeof(vis)) ;
	memset(dis,0x3f,sizeof(dis)) ;
	dis[s] = 0 , vis[s] = 0 ;
	q.push(make_pair(dis[s],s)) ;
	while(!q.empty()) {
		int u = q.top().second ;
		q.pop() ;
		if(vis[u]) continue ;
		vis[u] = 1 ;
		for(int i = head[u] ; i ; i = a[i].next) {
			int v = a[i].y ;
			if(dis[v] > dis[u] + a[i].z) {
				dis[v] = dis[u] + a[i].z ;
				q.push(make_pair(dis[v],v)) ;
			}
		}
	}
}
int main () {
	n = read() , m = read() ;
	for(int i = 1 ; i <= m ; i ++) {
		int x = read() , y = read() ;
		Add(y,x) ;
		fa[y].push_back(x) ;
	}
	s = read() , st = read();
	dfs(st);
	for(int i = 1 ; i <= n ; i ++) {
		if(!vis[i])
		for(int j = 0 ; j < fa[i].size() ; j ++) {
			book[fa[i][j]] = 1 ;
		}
	}
	for(int i = 1 ; i <= n ; i ++) {
		if(book[i]) vis[i] = 0 ;
	}
	for(int i = 1 ; i <= n ; i ++)
	t = 0 ;
	memset(head,0,sizeof(head)) ;
	for(int i = 1 ; i <= m ; i ++) {
		if(vis[b[i].x]) {
			add(b[i].y,b[i].x) ;
		}
	}
	dij(s) ;
	printf("%d\n",dis[st]>=dis[n+1] ? -1:dis[st]) ;
	return 0 ;
}

<mark> <mstyle mathcolor="yellow"> <mtext> 代码不解释 </mtext> </mstyle> \color{yellow}\text{代码不解释} 代码不解释</mark>