[NOIP2014]寻找道路 BFS+建图技巧

寻找道路
题目描述
1.预处理反向建边
2.从终点开始bfs,标记从终点开始可以走到的点。
3.枚举每一个点,如果这个点没有被标记,则枚举它的每一条出边(反向后的),如果它指向的点被标记,则说明这个被标记的点不合法,删除。
4.在合法点上进行bfs。

bfs有个性质是在第一次到达终点时的距离最短。

参考的题解
牛客题解

#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define INF 0x3f3f3f3f
#define PII pair<int, int>
#define rep(i, l, r) for (int i = l; i < r; i++)
#define per(i, l, r) for (int i = l; i >= r; i--)
#define rep2(i, l, r) for (int i = l; i * i <= r; i++)
#define rep3(i, l, r) for (LL i = l; i * i * i <= r; i++)
#define Min(a, b) a > b ? b : a
#define Max(a, b) a > b ? a : b
#define endl '\n'
#define debug "-----"
using namespace std;
typedef long long LL;
const LL mod = 1e9;
const int N = 1e6+10 ,M = 20100;
LL gcd(LL a, LL b) { return b ? gcd(b, a % b) : a; }

int n,m;
int s,e;
vector<int>mp[M];
bool st_can[N];
bool st[N];
int dist[N];

void bfs_end(){
	st_can[e] = 1;
	queue<int>q;
	q.push( e );
	while( q.size() ){
		int t = q.front();
		q.pop();
		rep( i , 0 , mp[t].size() )
			if( !st_can[ mp[t][i] ] ){
				st_can[ mp[t][i] ] = 1; //标记从终点可以到达的点
				q.push(mp[t][i]);
			}
	}
}

void bfs_beg(){
	queue<int> q;
	q.push(e);
	while (q.size())
	{
		int t = q.front();
		q.pop();
		rep(i, 0, mp[t].size()) 
			if ( st[mp[t][i]] )
			{
				q.push( mp[t][i] );
				st[mp[t][i]] = 0;
				dist[mp[t][i]] = dist[t] + 1;
			}
	}
}

int main(){
	cin >> n >> m;
	while(m--){
		int u,v;
		cin >> u >> v;
		if( u == v ) continue;//去除自环
		mp[v].push_back( u );
	}
	cin >> s >> e;

	bfs_end();
	memcpy( st , st_can , sizeof st_can );
	 //注意这里最好有第二个数组标记,在一个数组里删点有后效型。
	 //如果一个点开始被标记,它通过一个序号比它小的点删除了。
	 //那么访问到它的时候,就会被当成开始就没被标记的点,会通过它把合法点删除。
	rep( i , 1 , n+1 )
		if( !st_can[i] ){
			rep( j , 0 , mp[i].size() )
				if( st[ mp[i][j] ] ) st[ mp[i][j] ] = 0;
				//当一个点有其他不能到终点的点时,删去该点。
		}

	bfs_beg();

	if( dist[s] == 0 ) cout << -1;
	else cout << dist[s];
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值