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;
    }
  • 相关阅读:
    三个心态做人做学问 沧海
    成功走职场要找准自己的"快捷键" 沧海
    免费离线下载 拂晓风起
    Hibernate 获取某个表全部记录时 奇怪现象 (重复出现某个记录) 拂晓风起
    无法读取mdb 如果连接不了ACCESS mdb文件,就尝试安装MDAC 拂晓风起
    Netbeans 使用 Hibernate 逆向工程 生成hbm和pojo 拂晓风起
    如何点击单选框 radio 后面的文字,选中单选框 拂晓风起
    Java 连接access 使用access文件 不用配置 拂晓风起
    mysql下如何执行sql脚本 拂晓风起
    Hibernate配置access Hibernate 连接 access 拂晓风起
  • 原文地址:https://www.cnblogs.com/loi-frank/p/7714316.html
Copyright © 2011-2022 走看看