【题解】洛谷P2296 [NOIP2014]寻找道路

前往:我自己搭建的博客

题目

洛谷P2296寻找道路

题解

如果要确定一个点能否到达终点,就要从这个点开始搜索,想要确定所有的点,很耗时间。于是考虑反向操作,看从终点能倒着访问到哪些点。建一张反图(交换每条边的两个端点),从终点开始搜索,能够到达的点即是可以到终点的点。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int maxn=1e4+5;
const int maxm=2e5+5;
int n,m,c1,c2,s,t;
int h1[maxn],h2[maxn],d[maxn];
bool v[maxn],inq[maxn],can[maxn];	
//这里的inq[]表示是否进入过队列,can[]表示是否可以作为最短路径上的点 
struct edge{int to,nxt,w;}e1[maxm],e2[maxm];
inline void add1(int from,int to) 
{
	e1[++c1].to=to; e1[c1].nxt=h1[from]; h1[from]=c1;
}
inline void add2(int from,int to)
{
	e2[++c2].to=to; e2[c2].nxt=h2[from]; h2[from]=c2;
}
queue<int> q1;
inline void bfs()	//标记可以到达终点的点 
{
	q1.push(t); inq[t]=1;
	while(q1.size())
	{
		int x=q1.front(); q1.pop();
		for(int i=h2[x];i;i=e2[i].nxt)
		{
			int y=e2[i].to;
			if(!inq[y]) inq[y]=1,q1.push(y);
		}
	}
}
inline void get_point()	//标记可以位于路径上的点 
{
	for(int x=1;x<=n;x++)
	{
		can[x]=1;
		for(int i=h1[x];i;i=e1[i].nxt)
		{
			int y=e1[i].to;
			if(!inq[y]) {can[x]=0; break;}
		}
	}
}
priority_queue<pair<int,int> > q;
inline void dijkstra()
{
	memset(d,0x3f,sizeof(d));
	d[s]=0; q.push(make_pair(0,s));
	while(q.size())
	{
		int x=q.top().second; q.pop();
		if(v[x]) continue; v[x]=1;
		for(int i=h1[x];i;i=e1[i].nxt)
		{
			int y=e1[i].to;
			if(!can[y]) continue;
			if(d[y]>d[x]+1)
			{
				d[y]=d[x]+1;
				q.push(make_pair(-d[y],y));
			}
		}
	}
}
inline void solve()
{
	bfs(); get_point();
	dijkstra();
	if(d[t]==inf) printf("-1\n");
	else printf("%d\n",d[t]);
}

int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		int x,y; scanf("%d%d",&x,&y);
		add1(x,y); add2(y,x);
	}
	scanf("%d%d",&s,&t);
	solve();
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/zjgmartin/article/details/108415369