zoukankan      html  css  js  c++  java
  • 【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;
    }
  • 相关阅读:
    ubuntu安装-Docker(zz)
    vpp编译
    dpdk编译
    通过P4runtime进行解耦
    run p4 in mininet
    搭建基于Open vSwitch的VxLAN隧道实zz
    路由协议
    dNOS from AT&T
    《Java程序设计》实验一 Java开发环境的熟悉
    《Java程序设计》第五周学习总结
  • 原文地址:https://www.cnblogs.com/rlddd/p/9520601.html
Copyright © 2011-2022 走看看