Luogu P2296 寻找道路

https://www.luogu.org/problemnew/show/P2038

题目描述

在有向图 GG 中,每条边的长度均为 11,现给定起点和终点,请你在图中找一条从起点到终点的路径,该路径满足以下条件:

  1. 路径上的所有点的出边所指向的点都直接或间接与终点连通。
  2. 在满足条件11的情况下使路径最短。

注意:图 GG 中可能存在重边和自环,题目保证终点没有出边。

请你输出符合条件的路径的长度。

输入输出格式

输入格式:

第一行有两个用一个空格隔开的整数 nn 和 mm,表示图有 nn 个点和 mm 条边。

接下来的 mm 行每行 22 个整数 x,yx,y,之间用一个空格隔开,表示有一条边从点 xx 指向点yy。

最后一行有两个用一个空格隔开的整数 s, ts,t,表示起点为 ss,终点为 tt。

输出格式:

输出只有一行,包含一个整数,表示满足题目描述的最短路径的长度。如果这样的路径不存在,输出-1−1。

输入输出样例

输入样例#1: 复制

3 2  
1 2  
2 1  
1 3  

输出样例#1: 复制

-1

输入样例#2: 复制

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

输出样例#2: 复制

3

说明

解释1:

如上图所示,箭头表示有向道路,圆点表示城市。起点11与终点33不连通,所以满足题目描述的路径不存在,故输出-1−1 。

解释2:

如上图所示,满足条件的路径为11- >33- >44- >55。注意点22 不能在答案路径中,因为点22连了一条边到点66 ,而点66 不与终点55 连通。

【数据范围】

对于30\%30%的数据,0 < n \le 100<n≤10,0 < m \le 200<m≤20;

对于60\%60%的数据,0 < n \le 1000<n≤100,0 < m \le 20000<m≤2000;

对于100\%100%的数据,0 < n \le 10000, 0 < m \le 200000,0 < x,y,s,t \le n, x,s \ne t0<n≤10000,0<m≤200000,0<x,y,s,t≤n,x,s≠t。

反向建边,从终点bfs一遍,选出所有可以的节点

再跑一遍bfs,O(m),优秀

#include<cstdio>
using namespace std;
int read()
{
	int ret=0; char ch=getchar();
	while(ch<'0'||ch>'9') ch=getchar();
	while(ch>='0'&&ch<='9')
		ret=(ret<<1)+(ret<<3)+ch-'0',
		ch=getchar();
	return ret;
}

const int N=1e6+5;
int n,m,s,g,l,r,q[N],du[N],w[N];
bool fl[N],bj[N];
int cnt,to[N],nxt[N],he[N];
struct NA{
	int u,v;
}e[N];

inline void add(int u,int v)
{
	to[++cnt]=v;
	nxt[cnt]=he[u];
	he[u]=cnt;
}

int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		int u=read(),v=read();
		if(u!=v)
		{
			e[i].u=u,e[i].v=v,
			add(v,u),du[u]++;
		}
	}
	s=read(),g=read();
	l=r=1,q[1]=g,fl[g]=1,bj[g]=1;;
	while(l<=r)
	{
		int u=q[l]; 
		for(int e=he[u];e;e=nxt[e])
		{
			int v=to[e];
			if(!fl[v]) fl[v]=1,q[++r]=v,du[v]--;
				else if(fl[v]) du[v]--;
			if(!du[v]) bj[v]=1;
		}
		l++;
	}
	if(!bj[s]) 
	{
		puts("-1");
		fclose(stdin); fclose(stdout); 
		return 0;
	}
	cnt=0;
	for(int i=1;i<=n;i++) he[i]=fl[i]=0;
	for(int i=1;i<=m;i++)
		if(e[i].u&&e[i].v&&bj[e[i].v]&&bj[e[i].u]) 
			add(e[i].u,e[i].v);
	l=r=1,q[1]=s,fl[s]=1;
	while(l<=r)
	{
		int u=q[l];
		if(u==g) break;
		for(int e=he[u];e;e=nxt[e])
		{
			int v=to[e];
			if(!fl[v]&&bj[v])
				fl[v]=1,q[++r]=v,w[v]=w[u]+1;
		}
		l++;
	}
	if(!w[g]&&s!=g) puts("-1");
		else printf("%d\n",w[g]);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/YYHS_WSF/article/details/83271350