NOIp 2014 寻找道路

Description

有一张边权为 \(1\) 的有向图,可能有重边自环。

求一条从起点到终点的最短路径,满足路径上的所有点的出边所指向的点都直接或间接与终点连通。

比赛的时候做了这个题,感觉是道好题。

Solution

读入的时候保险起见特判掉环,貌似不特判也可以。

首先建反向边,从终点开始走,求出有哪些点能到终点。

然后暴力求出每个点能不能加入路径,即它的所有出边指向的点都能到达终点。

然后根据边权为 \(1\),在合法的点上跑 bfs 最短路。

可以用深搜实现反向建边 + bfs 预处理,写了发现被一个环卡住了。

所以类似于记忆化搜索的 dfs 预处理,可以考虑改成 bfs。

Code

#include <bits/stdc++.h>
using namespace std;
#define re register
#define F first
#define S second
typedef long long ll;
typedef pair<int, int> P;
const int INF = 0x3f3f3f3f;
const int N = 1e4 + 5, M = 2e5 + 5;
int read() {
    int x = 0, f = 0; char ch = 0;
    while (!isdigit(ch)) f |= ch == '-', ch = getchar();
    while (isdigit(ch)) x = (x << 3) + (x << 1) + (ch ^ 48), ch = getchar();
    return f ? -x : x;
}
struct edge{
    int to, nxt;
}e[M];
int head[M], tot, dis[N];
void addedge(int x, int y){
    e[++tot].to = y; e[tot].nxt = head[x]; head[x] = tot;
}
int start[N], to[N];
bool can[N], allcan[N], vis[N];
int main(){
    int n = read(), m = read();
    for (int i = 1; i <= m; i++){
        int x = read(), y = read();
        start[i] = x; to[i] = y;
        if (x != y) addedge(y, x);
    }
    int s = read(), t = read();
    queue <int> q; q.push(t); 
    while (!q.empty()){
        int x = q.front(); q.pop(); can[x] = 1;
        for (int i = head[x]; i; i = e[i].nxt){
            int y = e[i].to;
            if (!vis[y]){
                vis[y] = can[y] = 1;
                q.push(y);
            }
        }
    }
    memset(head, 0, sizeof(head)); memset(vis, 0, sizeof(vis)); tot = 0;
    for (int i = 1; i <= m; i++)
        if (start[i] != to[i]) addedge(start[i], to[i]);
    for (int x = 1; x <= n; x++) {
        allcan[x] = can[x];
        for (int i = head[x]; i; i = e[i].nxt) 
            allcan[x] &= can[e[i].to];
    }
        
    if (allcan[s]) q.push(s), vis[s] = 1;
    while (!q.empty()){
        int x = q.front(); q.pop();
        if (x == t){
            printf("%d\n", dis[t]);
            return 0;
        }
        for (int i = head[x]; i; i = e[i].nxt){
            int y = e[i].to;
            if (allcan[y] && !vis[y]){
                vis[y] = 1; q.push(y);
                dis[y] = dis[x] + 1;
            }
        }
    }
    puts("-1");
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/lyfoi/p/11443375.html