洛谷 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