【2014】

D2T2 寻找道路

一道相较于代码能力更考验思维的题。

首先我们要意识到只跟终点有关的特殊性质,跑反向图是很常见的操作。

因此这道题我们就是先从终点跑一遍反向图,把能到达终点的点标记出来,因为最后路径上的点绝对是从这些点中选,注意特判如果起点跑不到终点就直接输出-1然后return 0。

接下来枚举这些能到达终点的点,先将它们都标记为路径上的点,再枚举它们的每一条边的终点,这些(当前枚举点对应的)终点有一个不能到达题目所给的终点,那么把已标记点去掉标记,表明它不能出现在路径上。

最后bfs跑一个最短路,只能跑被标记的点即可。

#include<bits/stdc++.h>
#define ri register int
#define ll long long
#define For(i,l,r) for(ri i=l;i<=r;i++)
#define Dfor(i,r,l) for(ri i=r;i>=l;i--)
using namespace std;
const int M=1e5+5;
int dis[M],n,m,a,b,s,t;
bool path[M],can[M];
vector<int>side[M];
vector<int>edis[M];
queue<int>q;
inline ll read(){
    ll f=1,sum=0;
    char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){sum=(sum<<1)+(sum<<3)+(ch^48);ch=getchar();}
    return f*sum;
}
int main(){
    n=read(),m=read();
    For(i,1,m){
        a=read(),b=read();
        side[a].push_back(b);
        edis[b].push_back(a);
    }
    s=read(),t=read();
    can[t]=1;q.push(t);
    while(!q.empty()){
        int u=q.front();q.pop();
        for(int i=edis[u].size()-1;i>=0;i--){
            int v=edis[u][i];
            if(!can[v]){
                can[v]=1;
                q.push(v);
            }
        }
    }
    if(!can[s]){printf("-1\n");return 0;}
    For(i,1,n){
        if(can[i]){
            path[i]=1;
            for(int j=side[i].size()-1;j>=0;j--){
                int v=side[i][j];
                if(!can[v]){
                    path[i]=0;
                    break;
                }
            }
        }
    }
    if(!path[s]){printf("-1\n");return 0;}
    dis[s]=1;q.push(s);
    while(!q.empty()){
        int u=q.front();q.pop();
        if(u==t){printf("%d\n",dis[t]-1);return 0;}
        for(int i=side[u].size()-1;i>=0;i--){
            int v=side[u][i];
            if(path[v]&&!dis[v]){
                dis[v]=dis[u]+1;
                q.push(v);
            }
        }
    }
    printf("-1\n");
    return 0;
}
View Code

 

 

 

posted @ 2019-11-15 16:47  jian_song  阅读(124)  评论(0编辑  收藏  举报