【NOIP2014】P2296 寻找道路

一道比较基础的图遍历的题。
思路很巧妙,要考虑到反向建图,反向BFS,找出能达到终点的点1,再正向遍历,找到这些点1中出边点均能到终点的所有点2,然后再从起点遍历,只所有2类点中找最短路径

一开始总是TLE,后来发现是初始化建图时候没有考虑到重复操作,同一个点被处理了多次,时间耗时大大降低,见代码中关键优化一段

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#include <cmath>
using namespace std;
queue<int> qNode;
int n, m,x,y,s ,t;
vector<int> fwd[10005],rvs[10005];
int iCanReach[10005];
int iAllCan[10005] = { 0 };
int dis[10005];
inline int read()
{
	int x = 0, y = 1; char c = getchar();
	while (c>'9' || c<'0'){ if (c == '0')y = -1; c = getchar(); }
	while (c >= '0'&&c <= '9'){ x = x * 10 + c - '0'; c = getchar(); }
	return x*y;
}
int main()
{

	n = read();
	m = read();
	for (int i = 0; i < m; ++i)
	{
		x = read();
		y = read();
		if (x == y)continue;
		fwd[x].push_back(y);
		rvs[y].push_back(x);
	}
	s = read();
	t = read();
	qNode.push(t);
	while (!qNode.empty())
	{
		int node = qNode.front();
		qNode.pop();
		int isize = rvs[node].size();
		for (int it = 0; it < isize; ++it)
		{
			int num = rvs[node][it];
			if (!iCanReach[num])//关键的优化
			{
				qNode.push(num);
				iCanReach[num] = 1;
			}
			
		}
	}

	if (!iCanReach[s])
	{
		cout << -1;
		return 0;
	}
	iCanReach[t] = 1;
	for (int j = 1; j <= n; ++j)
	{
		if (iCanReach[j])
		{
			int isize = fwd[j].size();
			int it = 0;
			iAllCan[j] = 1;
			for (; it < isize; ++it)
			{
				if (!iCanReach[fwd[j][it]])
				{
					iAllCan[j] = 0; 
					break;
				}
					
			}
		}
	}

	if (!iAllCan[s])
	{
		cout << -1;
		return 0;
	}
	
	qNode.push(s);
	dis[s] = 0;
	while (!qNode.empty())
	{
		int node = qNode.front();
		qNode.pop();
		if (node == t)
		{
			cout << dis[t];
			return 0;
		}
		int isize = fwd[node].size();
		for (int it = 0; it <isize; ++it)
		{
			int itemp = fwd[node][it];
			if (iAllCan[itemp] && !dis[itemp])
			{
				qNode.push(itemp);
				dis[itemp]=dis[node] + 1;
			}
			
		}
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值