[noip2014]寻找道路

描述 Description

在有向图 G 中,每条边的长度均为 1,现给定起点和终点,请你在图中找一条从起点到终点的路径,该路径满足以下条件:
1.路径上的所有点的出边所指向的点都直接或间接与终点连通。
2.在满足条件 1 的情况下使路径最短。
注意:图 G 中可能存在重边和自环,题目保证终点没有出边。
请你输出符合条件的路径的长度。

输入输出格式

第一行有两个用一个空格隔开的整数 n 和 m,表示图有 n 个点和 m 条边。
接下来的 m 行每行 2 个整数 x、y,之间用一个空格隔开,表示有一条边从点 x 指向点y。
最后一行有两个用一个空格隔开的整数 s、t,表示起点为 s,终点为 t。
输出只有一行,包含一个整数,表示满足题目描述的最短路径的长度。如果这样的路径不存在,输出-1。
样例输入 Sample Input

输入样例1

3 2
1 2
2 1
1 3

输入样例2

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

输出样例1

-1

输出样例2

3

时间限制

1s

注释 Hint

输入输出样例1说明
[noip2014]寻找道路_第1张图片
如上图所示,箭头表示有向道路,圆点表示城市。起点 1 与终点 3 不连通,所以满足题目描述的路径不存在,故输出-1。
输入输出样例2说明
[noip2014]寻找道路_第2张图片
如上图所示,满足条件的路径为 1->3->4->5。注意点 2 不能在答案路径中,因为点 2连了一条边到点 6,而点 6 不与终点 5 连通。

数据说明

对于30%的数据,0 对于60%的数据,0 对于100%的数据,0

这道题的思路比较好想一些,我们可以建双向边,对于正边和反边我们标记一下即可。
那么建完边后我们先从终点bfs一遍,只跑反向边,对于每个遍历到的边进行标记,这样我们就可以找出不能直接或间接到达终点的点。
得到这些点后,我们再遍历这些点的反向边的出边,将与这些点相连的点进行标记。
标记完后我们剩下的没有被第二次标记的点就是可以走的点。这时我们再从起点bfs一遍,只跑正向边,且不走被第二次标记过的点,那么第一次到达终点的时候就是可到达的最短路。

#include

#define ll long long
#define MAXN 500010
#define N 201
#define INF 0x7f7f7f7f
#define gtc() getchar()

using namespace std;

template <class T>
inline void read(T &s){
	s = 0; T w = 1, ch = gtc();
	while(!isdigit(ch)){if(ch == '-') w = -1; ch = gtc();}
	while(isdigit(ch)){s = s * 10 + ch - '0'; ch = gtc();}
	s *= w;
}

template <class T>
inline void write(T x){
    if(x < 0) putchar('-'), x = -x;
	if(x > 9) write(x/10);
    putchar(x % 10 + '0');
}

struct node{
	int y, ne, z;
}e[MAXN];

int lin[MAXN], len = 0;
inline void add(int x, int y, int z){
	e[++len].y = y, e[len].ne = lin[x], lin[x] = len;
	e[len].z = z;
}

int n, m;
int st, ed;

int col[MAXN], vis[MAXN];

void bfs(int u){
	queue<int> q;
	q.push(u);
	vis[u] = 1;
	while(!q.empty()){
		int x = q.front(); q.pop();
		for(int i = lin[x]; i; i = e[i].ne){
			int y = e[i].y; 
			if(e[i].z == 1) continue;
			if(vis[y]) continue;
			vis[y] = 1;
			q.push(y);
		}
	}
}

void bfs2(int u){//这个不是bfs,之前写错写成bfs,后来直接在这个函数里改了。
	col[u] = 1;
	for(int i = lin[u]; i; i = e[i].ne){
		int y = e[i].y;
		if(e[i].z == 1) continue;
		if(col[y]) continue;
		col[y] = 1;
		q.push(y);
	}
}

int dis[MAXN];
void bfs3(int u){
	memset(dis, INF, sizeof(dis));
	dis[u] = 0;
	queue<int> q;
	q.push(u);
	while(!q.empty()){
		int x = q.front(); q.pop();
		for(int i = lin[x]; i; i = e[i].ne){
			int y = e[i].y;
			if(e[i].z == 2) continue;
			if(col[y]) continue;
			if(dis[y] != INF) continue;
			dis[y] = dis[x] + 1;
			q.push(y);
		}
	}
}

int main()
{
	read(n), read(m);
	int x, y;
	for(int i = 1; i <= m; ++i){
		read(x), read(y);
		add(x, y, 1); add(y, x, 2);//1为正边,2为负边
	}
	read(st), read(ed);
	bfs(ed);
	for(int i = 1; i <= n; ++i){
		if(!vis[i]){
			bfs2(i);
		}
	}
	bfs3(st);	
	if(dis[ed] == INF) puts("-1");
	else printf("%d\n", dis[ed]);
	return 0;
}

你可能感兴趣的:(noip)