洛谷 P2296 [NOIP2014 提高组] 寻找道路(反图bfs)

传送门


解题思路

首先明白题意:
能经过的点必须满足其所有连向的节点都能走到终点。
于是我们就可以建个反图,跑一遍dfs,求出有多少满足条件的点,最后bfs跑一遍即可。
如何判断?
用一个num数组表示节点i在原图的出度,即在反图的出度。
每当有一个点指向节点i时,num[i]--。
最后若num[i]为0则满足条件。
注意因为有环,所以要记录vis数组,保证每个节点只会使其连向的节点最多减少一。

AC代码

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
const int maxm=200005;
int n,m,s,t,vis[10005],p[10005],cnt,dis[10005],num[10005];
queue<int> q;
struct node{
	int v,next;
}e[maxm*2];
void insert(int u,int v){
	cnt++;
	e[cnt].v=v;
	e[cnt].next=p[u];
	p[u]=cnt;
}
void dfs(int u){
	vis[u]=1;
	for(int i=p[u];i!=-1;i=e[i].next){
		int v=e[i].v;
		num[v]--;
		if(vis[v]) continue;
		dfs(v);
	}
}
int main(){
	memset(p,-1,sizeof(p));
	ios::sync_with_stdio(false);
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		int u,v;
		cin>>u>>v;
		insert(v,u);
		num[u]++;
	}
	cin>>s>>t;
	dfs(t);
	memset(vis,0,sizeof(vis));
	q.push(t);
	vis[t]=1;
	while(!q.empty()){
		int u=q.front();
		q.pop();
		for(int i=p[u];i!=-1;i=e[i].next){
			int v=e[i].v;
			if(num[v]!=0||vis[v]) continue;
			vis[v]=1;
			dis[v]=dis[u]+1;
			q.push(v); 
			if(v==s){
				cout<<dis[s];
				return 0;
			}
		}
	}
	cout<<-1;
    return 0;
}

//NOIP2014提高组Day2 t2

posted @ 2021-07-27 23:55  尹昱钦  阅读(38)  评论(0编辑  收藏  举报