洛谷P2296题解

原题

P2296 [NOIP2014 提高组] 寻找道路


思路概述

题意分析

给定包含 \(n\) 个点和 \(m\) 条有向边的图 \(G(V,E)\),求从起点 \(s\) 到终点 \(t\) 的最短合法路径。一条路径是合法路径当且仅当路径上所有点出边的顶点与终点 \(t\) 连通。

思路简述

考虑到对于合法路径的定义较为复杂,需要先在图中筛选出合法路径上的“合法点”。

由于一个合法点的条件是其所有出边的顶点与终点连通,而本题输入的是有向图,所以考虑先反向建图,标记出原图中所有能与终点连通的点,再判定每一个点是否是合法点(即该点与其出边的顶点能否与终点连通)。

判定出合法点后用广搜处理最短路即可。


算法实现

关于建图

由于本题需要建正反向两个图,所以笔者建议将图封装成结构体,连边时调用内部函数即可。

关于广搜求最短路

需要一个辅助数组记录当前所有点到起点的距离。

由于广搜是多条路径同时搜索,所以当前搜索到的点与起点的距离必然是最短路径长度;相应地,若一个点被搜索到时其最短路长度已经被更新,就说明该点不需要再被考虑。

其他注意事项

输入数据存在重边和自环,输入时需要判定。


AC code

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<set>
#include<ctime>
#include<map>
#define RI register int
using namespace std;
const int maxn=2e5+10;
typedef struct
{
	int u,nex;
}side;
typedef struct
{
	side s[maxn];
	int cnt;
	int fir[maxn];
	inline void add(int x,int y){s[++cnt]=(side){y,fir[x]};fir[x]=cnt;return;}
}graph;
graph g,rg;
int n,m,s,t;
int dis[maxn];
bool avl[maxn],rec[maxn];
map<pair<int,int>,bool> mp;
inline void bfs_rvr(void);
inline void bfs(void);
int main()
{
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	cin >> n >> m;
	for(RI i=1,x,y;i<=m;++i)
	{
		cin >> x >> y;
		if(x!=y && !mp[make_pair(x,y)])/*判下重边和自环*/ 
		{
			g.add(x,y);rg.add(y,x);
			mp[make_pair(x,y)]=1;
		}
	}
	cin >> s >> t;
	bfs_rvr();/*筛选合法点*/
	if(!avl[s]) puts("-1");
	else
	{
		bfs();/*广搜求最短路*/
		printf("%d",dis[t]);		
	}
	fclose(stdin);fclose(stdout);
	return 0;
}
inline void bfs_rvr(void)
{
	queue<int> q;
	q.push(t);avl[t]=1;
	for(;!q.empty();)
	{
		RI temp=q.front();q.pop();
		for(RI i=rg.fir[temp];i;i=rg.s[i].nex)
			if(!avl[rg.s[i].u])
			{
				avl[rg.s[i].u]=1;
				q.push(rg.s[i].u);
			}
	}
	if(!avl[s]) return;
	else
	{
		for(RI i=1;i<=n;++i) rec[i]=1;
		for(RI i=1;i<=n;++i)
			for(RI j=g.fir[i];j;j=g.s[j].nex)
				if(!avl[g.s[j].u])
				{
					rec[i]=0;
					break;
				}
	}
	return;
}
inline void bfs(void)
{
	queue<int> q;q.push(s);
	for(;!q.empty();)
	{
		RI temp=q.front();q.pop();
		if(temp==t) break;
		else
			for(RI i=g.fir[temp];i;i=g.s[i].nex)
				if(rec[g.s[i].u] && !dis[g.s[i].u])
				{
					dis[g.s[i].u]=dis[temp]+1;
					q.push(g.s[i].u);
				}
	}
	return;
}

posted @ 2022-10-26 12:14  UOB  阅读(50)  评论(0编辑  收藏  举报