【图论】B063_AW_寻找道路(建反图+dfs预处理连通性+bfs求最短路)

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

1.路径上的所有点的出边所指向的点都直接或间接与终点连通。
2.在满足条件1的情况下使路径最短。

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

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

输入格式
第一行有两个用一个空格隔开的整数n和m,表示图有n个点和m条边。
接下来的m行每行2个整数x、y,之间用一个空格隔开,表示有一条边从点x指向点y。
最后一行有两个用一个空格隔开的整数s、t,表示起点为s,终点为t。

输出格式
输出只有一行,包含一个整数,表示满足题目描述的最短路径的长度。
如果这样的路径不存在,输出-1。
数据范围
0 0 0

输入样例:
6 6  
1 2  
1 3  
2 6  
2 5  
4 5  
3 4  
1 5  
输出样例:
3
方法一:dfs+bfs

读了第五遍,依旧没get到题目的意思,直到,看到了特殊点:所求最短路径上的点的所有出边都要间接或直接的指向终点。emmm…

这样就好办了,正反图都建一遍,然后 dfs 从终点出发,枚举能到达的结点,这些点就是特殊点。

#include
using namespace std;
const int N=1e5+5, inf=-1;
vector<int>g1[N], g2[N];
int n,m,s,e, d[N],vis[N];
void dfs(int u) {
     
    vis[u]=1;
    for (int v : g2[u]) if (!vis[v]) {
     
        vis[v]=1;
        dfs(v);
    }
}

bool chk(int u) {
        //检查u点是否直接或间接与e相连
    for (int v : g1[u]) if (!vis[v])
        return false;
    return true;
}

bool bfs(int s) {
     
    memset(d, inf, sizeof d);
    queue<int> q; q.push(s), d[s]=0;
    while (!q.empty()) {
     
        int u=q.front(); q.pop();
        if (!chk(u)) continue;
        if (u==e) return true;
        for (int v : g1[u]) {
     
            if (d[v]==inf) {
     
                d[v]=d[u]+1;
                q.push(v);
            }
        }
    }
    return false;
}

int main() {
     
    std::ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    cin>>n>>m; memset(d, inf, sizeof d);
    for (int i=0; i<m; i++) {
     
        int a,b; cin>>a>>b;
        g1[a].push_back(b);
        g2[b].push_back(a);
    }
    cin>>s>>e;
    dfs(e);
    if (bfs(s)) cout << d[e];
    else        cout << -1;
    return 0;
}

复杂度分析

  • Time O ( n m ) O(nm) O(nm)
  • Space O ( n m ) O(nm) O(nm)

你可能感兴趣的:(【图论】B063_AW_寻找道路(建反图+dfs预处理连通性+bfs求最短路))