题解 P2296 【寻找道路】

· · 题解

一遍AC,,本蒟蒻表示很开心

论如何找到可以走的点:

先从终点反向遍历一次,并把遍历到的点打个good标记;

如果起点没有good标记,就代表到不了起点,那么就输出-1

然后在循环找一遍所以的没有good标记的点,并对其直接相连的点打上can标记,即不能使用

最后就愉快的再一次BFS,一旦遍历到终点,就输出ans

#include<bits/stdc++.h>
using namespace std;
struct abc{
    int date,next;
};
int n,m,head[11000],headback[11000],ans[11000],tot,totback,s,t;
abc chain[201000],chainback[201000];
int q[11000];bool may[11000],good[11000],can[11000];
int read()
{
    char c;int x=0;
    c=getchar();
    while(c>'9'||c<'0')c=getchar();
    while(c<='9'&&c>='0')x=x*10+c-'0',c=getchar();
    return x;
}
void add(int from,int want)//加边
{
    tot++;
    chain[tot].date=want;
    chain[tot].next=head[from];
    head[from]=tot;
}
void addback(int from,int want)//反向加边
{
    totback++;
    chainback[totback].date=want;
    chainback[totback].next=headback[from];
    headback[from]=totback;
} 
void first()//找出所有好点 
{
    int want,now,he=0,tail=1;
    q[1]=t;
    good[t]=true;
    while(he!=tail)
    {
        he++;
        want=headback[q[he]];
        now=chainback[want].date;
        while(now)//进行拓展
        {
            if(!good[now])//如果还没有被遍历过就加入队列
            {
                good[now]=true;
                q[++tail]=now;
            }
            want=chainback[want].next;
            now=chainback[want].date;
        }
    }
    if(!good[s])//如果到不了起点
    {
        printf("-1");
        exit(0);
    }
}
void second()
{
    int he=0,tail=1,i,now,want;
    memset(q,0,sizeof(q));
    q[1]=s;
    may[s]=true;
    while(he!=tail)
    {
        he++;
        want=head[q[he]];
        now=chain[want].date;
        while(now)
        {
            if(!good[now]||can[now])//如果这个点右边是坏的,或者本身就是坏的(貌似这个判断是多余的?因为与坏点相连的点根本进不来)
            {
                want=chain[want].next;
                now=chain[want].date;    
                continue;
            }
            if(!may[now])//如果没被访问过
            {
                may[now]=true;//标记已访问
                q[++tail]=now;//加入队列
                ans[now]=ans[q[he]]+1;//记录ans,由于BFS特性,直接+1即可
            }
            want=chain[want].next;
            now=chain[want].date;
        }
    }
}
void mid()//标记所有坏点 
{
    int now,want,i;
    for(i=1;i<=n;i++)
    {
        if(!good[i])//如果不是好点 
        {
            want=headback[i];
            now=chainback[want].date;
            while(now)
            {
                can[now]=true;//标记 
                want=chainback[want].next;
                now=chainback[want].date;
            }
        }
    } 
}
int main()
{
    int i,a,b;
    scanf("%d%d",&n,&m);
    for(i=1;i<=m;i++)
    {
        a=read();b=read();
        add(a,b);
        addback(b,a);//用于反向预处理 
    }
    scanf("%d%d",&s,&t);
    first();
    mid();
    second();
    printf("%d",ans[t]);//输出到t的最短距离
    return 0;
}