[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

提示

解释1:

如上图所示,箭头表示有向道路,圆点表示城市。起点$1 $与终点$3 \(不连通,所以满足题目描述的路径不存在,故输出\)-1$ 。

解释2:

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

数据范围

对于\(30\%\)的数据,\(0 < n \le 10\)\(0 < m \le 20\);

对于\(60\%\)的数据,\(0 < n \le 100\)\(0 < m \le 2000\);

对于\(100\%\)的数据,\(0 < n \le 10000, 0 < m \le 200000,0 < x,y,s,t \le n, x,s \ne t\)

Solution:

将与终点不连通的边删掉,在剩下的图中跑最短路即可

注意:

  • 删掉终点不连通的边,即删去与终点不连通的点的入边,不是连通块
  • 删边操作可反向建图,从终点遍历,无法遍历到的是与终点不连通的点

时间复杂度: \(O(n+mlogn)\)

Code:

#include <cstdio>
#include <algorithm>
#include <queue>
#include <cstring>

using namespace std;

typedef pair<int,int> PII;

const int N=10005,M=400005,INF=0x3f3f3f3f;
int n,m,S,T;
int idx,h[N],rh[N],dis[N];
int st[N];

struct node
{
    int nxt,to;
}e[M];

void add(int h[],int nxt,int to)
{
    e[++idx].nxt=h[nxt];
    e[idx].to=to;
    h[nxt]=idx;
}
void dfs(int u,int col)
{
    if(st[u]==col)return;
    st[u]=col;
    for(int i=rh[u];~i;i=e[i].nxt)
    {
        int v=e[i].to;
        dfs(v,col);
    }
}
int dijk()
{
    priority_queue<PII,vector<PII>,greater<PII>> q;
    memset(st,0,sizeof(st));
    memset(dis,0x3f,sizeof(dis));
    dis[S]=0;
    q.push({0,S});

    while(q.size())
    {
        int u=q.top().second;
        q.pop();

        if(st[u])continue;
        st[u]=1;

        for(int i=h[u];~i;i=e[i].nxt)
        {
            int v=e[i].to;
            if(dis[v]>dis[u]+1)
            {
                dis[v]=dis[u]+1;
                q.push({dis[v],v});
            }
        }
    }
    if(dis[T]<INF)return dis[T];
    return -1;
}
int main()
{
    scanf("%d%d",&n,&m);
    
    memset(h,-1,sizeof(h));
    memset(rh,-1,sizeof(rh));
    for(int i=0;i<m;++i)
    {
        int a,b,c;
        scanf("%d%d",&a,&b);
        add(rh,b,a);
    }
    scanf("%d%d",&S,&T);

    dfs(T,1);

    for(int i=1;i<=n;++i)
        if(st[i]==0)
        {
            for(int j=rh[i];~j;j=e[j].nxt)
                if(e[j].to!=S && e[j].to!=T)
                    st[e[j].to]=2;
            st[i]=2;
        }
    
    for(int i=1;i<=n;++i)
    {
        if(st[i]==2)continue;
        for(int j=rh[i];~j;j=e[j].nxt)
        {
            int v=e[j].to;
            if(st[v]==2)continue;
            add(h,v,i);
        }
    }
    
    printf("%d\n",dijk());
    return 0;
}
posted @ 2022-10-05 20:48  FighterQ  阅读(118)  评论(0)    收藏  举报