LGOJ P2296 【寻找道路】

题目描述

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

路径上的所有点的出边所指向的点都直接或间接与终点连通。
在满足条件\(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 100\)\(0 < m \le 200\);

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

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




問題の解

思路比较直接:

1° 建反图,从\(t\)开始\(dfs\),以得到所有能到达到\(t\)的点,用\(rc[]\)数组记录。\(rc[u]==1\)表示\(u\)能直接或间接到达\(t\)

//vector<int> RG[N];表示反图
void dfs(int u)
{
    rc[u]=1;
    for(int i=0;i<RG[u].size();i++)
    {
        int v=RG[u][i];
        if(rc[v]==0)dfs(v);
    }
}
                                   

2° 探究每一个点\(u\)是否能被选择(能否参与构成路径),用\(sel[]\)数组记录。\(sel[u]==1\)表示\(u\)是可以出现在路径上的点。枚举\(u\)的出边,求\(sel[u]\):

\[sel[u]=rc[v_1] \& rc[v_2] \&...\&rc[v_{end}]. \]

其中,\(v_1,v_2,...v_{end}\)\(u\)的出边直连的点;\(\&\)是逻辑与运算符;

//vector<int> G[N];表示原图
for(int u=1;u<=n;u++)
{
    for(int i=0;i<G[u].size();i++)
    {
       	int v=G[u][i];
        sel[u]&=rc[v];
    }
}

3° 对于所有\(sel[vertex]==1\)的点,跑\(Dijkstra\)模板。

完整代码:

#include<bits/stdc++.h>
using namespace std;

inline int read()
{
    char c=getchar();int x=0;
    for(;!isdigit(c);c=getchar());
    for(;isdigit(c);c=getchar())
        x=x*10+c-'0';
    return x;
}
const int N=10005,M=200005,INF=0x3f3f3f3f;
bool rc[N],GG[N][N],sel[N];
int d[N];
int n,m,s,t;
vector<int> G[N];
vector<int> RG[N];
bool vis[N];
priority_queue< pair<int,int> >Q;

void dfs(int u)
{
    rc[u]=1;
    for(int i=0;i<RG[u].size();i++)
    {
        int v=RG[u][i];
        if(rc[v]==0)dfs(v);
    }
}

void dijk()
{
    for(int i=1;i<=n;i++)d[i]=INF;
    memset(vis,0,sizeof(vis));
    d[s]=0;
    Q.push(make_pair(0,s));
    if(sel[s]==0)return;
    while(!Q.empty())
    {
        int u=Q.top().second;
        Q.pop();
        if(vis[u])continue;
        vis[u]=1;
        for(int i=0;i<G[u].size();i++)
        {
            int v=G[u][i];
            if(sel[v]&&d[v]>d[u]+1)
            {
                d[v]=d[u]+1;
                Q.push(make_pair(-d[v],v));
            }
        }
    }
}

int main()
{
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
        int u=read();
        int v=read();
        if(u==v)continue;
        if(GG[u][v])continue;
        GG[u][v]=1;
        G[u].push_back(v);
        RG[v].push_back(u);
    }
    cin>>s>>t;
    dfs(t);
    for(int i=1;i<=n;i++)sel[i]=1;
    for(int u=1;u<=n;u++)
    {
        for(int i=0;i<G[u].size();i++)
        {
            int v=G[u][i];
            sel[u]&=rc[v];
        }
    }
    dijk(); 
    if(d[t]!=INF)cout<<d[t];
    else cout<<"-1";
	return 0;
}

posted @ 2019-11-08 10:45  miyasaka  阅读(130)  评论(0)    收藏  举报