【noip】2014年复赛提高组day2:寻找道路(road)

 由于本题有一个条件是路径上的所有点的出边所指向的点都直接或间接与终点连通,所以可以先从终点开始(倒着存边)用  bfs搜一遍,把每个可以从终点到达的点标记一下,然后把能直接到达未被标记的点的那些点也给添加标记。

注意(っ*′Д`)っ(非常非常重要!!!):这里用另一个vis数组标记,因为这里的标记有后效性,会把能间接到达未被标记的点的那些点也标记上。之后再进行一次bfs,记录最短路径长度。

  具体看代码:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int n,m,s,t,d[20000],xx[20000],a,to[300000],next[300000],head[300000];
bool f[20000],z[20000],vis[20000];
void bfs1(int x)
{
	int h=0,t=1;
	d[1]=x;  f[x]=1;
	while(h<t)
	{
		h++;  x=d[h];  z[x]=1;
		for(int i=head[x];i>0;i=next[i])
		  if(f[to[i]]==0)
		  {
			f[to[i]]=1;
			t++;
			d[t]=to[i];
		  }
	}
}
void bfs2(int x)
{
	int h=0,t=1;
	d[1]=x;  f[x]=1;
	while(h<t)
	{
		h++;  x=d[h];
		for(int i=head[x];i>0;i=next[i])
		{
			if(z[to[i]]==0||f[to[i]]==1)  continue;
			f[to[i]]=1;
			t++;
			d[t]=to[i];
			xx[to[i]]=xx[x]+1;
		}
	}
}
int main()
{
	cin>>n>>m;
	for(int i=1;i<=m;i++)
	{
		cin>>to[i]>>a;    //倒存边。
		next[i]=head[a];
		head[a]=i;
	}
	cin>>s>>t;
    bfs1(t);
    memset(f,0,sizeof(f));
    for(int i=1;i<=n;i++)  vis[i]=z[i];    //用另一个数组存非常关键!!!
    for(int i=1;i<=n;i++)
      if(vis[i]==0)
        for(int j=head[i];j>0;j=next[j])
          z[to[j]]=0;
    bfs2(t);    //由于是存倒边,所以只能从终点开始。
    if(xx[s]==0)  cout<<"-1";
    else         cout<<xx[s];
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42192786/article/details/82949761
今日推荐