【noip2014】寻找道路

题目描述

在有向图 G 中,每条边的长度均为 1,现给定起点和终点,请你在图中找一条从起点到 终点的路径,该路径满足以下条件:

  1. 路径上的所有点的出边所指向的点都直接或间接与终点连通。
  2. 在满足条件 1 的情况下使路径最短。

注意:图 G 中可能存在重边和自环,题目保证终点没有出边。 请你输出符合条件的路径的长度。


输入

第一行有两个用一个空格隔开的整数 n 和 m,表示图有 n 个点和 m 条边。

接下来的 m 行每行 2 个整数 x、y,之间用一个空格隔开,表示有一条边从点 x 指向点y。

最后一行有两个用一个空格隔开的整数 s、t,表示起点为 s,终点为 t。


输出

输出只有一行,包含一个整数,表示满足题目描述的最短路径的长度。

如果这样的路径不存在,输出-1。


样例输入1

3 2
1 2
2 1
1 3

样例输出1

-1

样例输入2

6 6
1 2
1 3
2 6
2 5
4 5
3 4
1 5

样例输出2

3

 

对于 30%的数据,0 < n ≤ 10,0 < m ≤ 20;

对于 60%的数据,0 < n ≤ 100,0 < m ≤ 2000;

对于 100%的数据,0 < n ≤ 10,000,0 < m ≤ 200,000,0 < x,y,s,t ≤ n,x ≠ t。

 



题解

考虑当前结点u能不能走,遍历u的所有出边连向v,如果有一个v不与终点直接或间接连通,那么u就不能走。

所以我们想要知道图中任意一点与终点的连通情况。观察数据:60%的点可以用floyd,100%的点我们就只能用spfa。首先反向建图,从终点做一遍spfa,如果终点到某个点的最短路等于inf,那么他们不连通。

然后正向建图。预处理出n个点哪些可以走哪些不能走,再从起点做一边spfa,只经过可以走的点,算出最短路就ok。

 

#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long

const int maxn=10000+50;
const int maxm=200000+50;
const int maxx=2139062143;

int n,m,x[maxm],y[maxm],s,t;
int fir[maxn],to[maxm],nex[maxm],wi[maxm],ecnt;
int c[maxn],q[2000001];
bool p[maxn],dis[maxn][maxn],u[maxn];

template<typename T>void read(T& aa){
    char cc; ll ff;aa=0;cc=getchar();ff=1;
    while((cc<'0'||cc>'9')&&cc!='-') cc=getchar();
    if(cc=='-') ff=-1,cc=getchar();
    while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar();
    aa*=ff;
}

void add_edge(int u,int v){
    nex[++ecnt]=fir[u];fir[u]=ecnt;to[ecnt]=v;wi[ecnt]=1;
}

void spfa(int x){
    int head=0,tail=1;
    memset(p,false,sizeof(p));
    memset(c,127,sizeof(c));
    p[x]=true;
    c[x]=0;
    q[1]=x;
    while(head<tail){
        head++;
        int u=q[head];
        p[u]=false;
        for(int e=fir[u];e;e=nex[e]){
            int v=to[e];
            if(c[u]+wi[e]<c[v]){
                c[v]=c[u]+wi[e];
                if(!p[v]){
                    tail++;
                    p[v]=true;
                    q[tail]=v;
                }
            }
        }
    }
}

void spfa1(int x){
    int head=0,tail=1;
    memset(p,false,sizeof(p));
    memset(c,127,sizeof(c));
    p[x]=true;
    c[x]=0;
    q[1]=x;
    while(head<tail){
        head++;
        int uu=q[head];
        p[uu]=false;
        for(int e=fir[uu];e;e=nex[e]){
            int v=to[e];
            if(u[v]&&c[uu]+wi[e]<c[v]){
                c[v]=c[uu]+wi[e];
                if(!p[v]){
                    tail++;
                    p[v]=true;
                    q[tail]=v;
                }
            }
        }
    }
}

int main(){
    memset(dis,false,sizeof(dis));
    memset(u,true,sizeof(u));
    read(n),read(m);
    for(int i=1;i<=m;i++){
        read(x[i]),read(y[i]);
        add_edge(y[i],x[i]);
    }
    read(s),read(t);
    spfa(t);
    for(int i=1;i<=n;i++)
    if(c[i]<maxx) dis[i][t]=true;
    memset(fir,0,sizeof(fir));
    memset(to,0,sizeof(to));
    memset(wi,0,sizeof(wi));
    memset(nex,0,sizeof(nex));ecnt=0;
    for(int i=1;i<=m;i++) add_edge(x[i],y[i]);
    for(int i=1;i<=n;i++)
    if(i!=t){
        for(int e=fir[i];e;e=nex[e]){
            int v=to[e];
            if(!dis[v][t]){
                u[i]=false;
                break;
            }
        }
    }
    if(!u[s]){
        cout<<"-1"<<endl; return 0;
    }
    spfa1(s);
    if(c[t]==maxx) cout<<"-1"<<endl;
    else cout<<c[t]<<endl;
    return 0;
}

 

posted @ 2018-08-22 21:47  rld  阅读(156)  评论(0编辑  收藏  举报