zoukankan      html  css  js  c++  java
  • NOIP2014 寻找道路

    题目描述

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

    1 .路径上的所有点的出边所指向的点都直接或间接与终点连通。

    2 .在满足条件1 的情况下使路径最短。

    注意:图G 中可能存在重边和自环,题目保证终点没有出边。

    请你输出符合条件的路径的长度。

    输入输出格式

    输入格式:

    输入文件名为road .in。

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

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

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

    输出格式:

    输出文件名为road .out 。

    输出只有一行,包含一个整数,表示满足题目᧿述的最短路径的长度。如果这样的路径不存在,输出- 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

    说明

    解释1:

    如上图所示,箭头表示有向道路,圆点表示城市。起点1 与终点3 不连通,所以满足题

    目᧿述的路径不存在,故输出- 1 。

    解释2:

    如上图所示,满足条件的路径为1 - >3- >4- >5。注意点2 不能在答案路径中,因为点2连了一条边到点6 ,而点6 不与终点5 连通。

    对于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。

    思路:当我第一眼看这道题时,我原以为D2T2肯定比较难,结果再看了看发现:WTF?这真的是D2T2难度??哎呀不说了,大水题一个。

    想法很简单,既然要判断每个点与终点是否联通,(以下为我一本正经的口胡)我们可以考虑用并查集(这样真的好吗?),但是这是有向图,那怎么办呢?我们发现,终点是不变的,而且只需判断终点与其他点

    的联通性,那我们可以用一个技巧:把所有的边都反向,然后从终点跑一遍BFS,遍历全图,这样,没有被访问过的点就一定与终点不连通。为什么要用这种方法呢?因为如果边是正向,那么我们定会让每个点都跑

    一遍BFS,无疑会TLE,考虑到从一个点出发能到达所有联通的点,那么我们可以反向BFS(实质是原来的起点与终点互换位置)。

    处理完联通性后,我们对所有的与终点不连通的点进行反向出边遍历(名词是自己造的QAQ),对遍历到的点标记为不合法(因为我们这条路要满足条件1),这样的话,再从起点s正向跑一遍SPFA,当遇到不合法的

    点时就跳过,然后dist[ed]或-1就是最后的答案。(到达不了就是-1)。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    using namespace std;
    const int N=10000+5;
    const int M=2e5+5;
    int read()
    {
        int ret=0,f=1;
        char c=getchar();
        while(c<'0'||c>'9')
        {if(c=='-') f=-1;c=getchar();}
        while(c>='0'&&c<='9')
        {ret=ret*10+c-'0';c=getchar();}
        return ret*f;
    }
    int n,m;
    struct edge{
        int from,to;
    }e1[M],e2[M];
    int head1[N],nxt1[M],tot1=0;
    int head2[N],nxt2[M],tot2=0;
    bool vis[N],np[N];
    void adde(int f,int t)
    {
        e1[++tot1]=(edge){f,t};
        e2[++tot2]=(edge){t,f};
        nxt1[tot1]=head1[f];
        nxt2[tot2]=head2[t];
        head1[f]=tot1;
        head2[t]=tot2;
    }
    queue<int > q;
    int dist[N];
    bool inq[N];
    void bfs(int s)
    {
        vis[s]=1;
        q.push(s);
        while(!q.empty())
        {
            int u=q.front();
            q.pop();
            for(int i=head2[u];i;i=nxt2[i])
            {
                int v=e2[i].to;
                if(!vis[v]) q.push(v),vis[v]=1;
            }
        }
    }
    void solve()
    {
        for(int i=1;i<=n;i++)
        {
            if(!vis[i])
            {
                for(int j=head2[i];j;j=nxt2[j])
                {
                    int v=e2[j].to;
                    np[v]=1;
                }
            }
        }
    }
    
    void spfa(int s)
    {
        dist[s]=0;
        q.push(s);
        inq[s]=1;
        while(!q.empty())
        {
            int u=q.front();
            q.pop();
            inq[u]=0;
            for(int i=head1[u];i;i=nxt1[i])
            {
                int v=e1[i].to;
                if(np[v]) continue;
                if(dist[v]>dist[u]+1)
                {
                    dist[v]=dist[u]+1;
                    if(!inq[v])
                    {
                        q.push(v);
                        inq[v]=1;
                    }
                }
            }
        }
    }
    int main()
    {
        memset(dist,0x3f,sizeof(dist));
        n=read(),m=read();
        int a,b;
        for(int i=1;i<=m;i++)
        {
            a=read(),b=read();
            adde(a,b);
        }
        int st,ed;
        st=read(),ed=read();
        bfs(ed);
        solve();
        spfa(st);
        int ans=(dist[ed]>1e9?-1:dist[ed]);
        printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    C++ 构造函数初始化列表
    虚函数
    thread 学习
    vim学习笔记
    Python重载比较运算符
    python使用插入法实现链表反转
    【好文转】Python中yield的理解与使用
    【转】Python中自定义可迭代对象
    linux安装python3.6.6和新建虚拟环境
    【转】Python 并行分布式框架 Celery
  • 原文地址:https://www.cnblogs.com/loi-frank/p/7714316.html
Copyright © 2011-2022 走看看