1. 程式人生 > >P2296 尋找道路(dfs+spfa)

P2296 尋找道路(dfs+spfa)

洛谷 P2296 尋找道路

題目描述

在有向圖 GG 中,每條邊的長度均為 11,現給定起點和終點,請你在圖中找一條從起點到終點的路徑,該路徑滿足以下條件:

路徑上的所有點的出邊所指向的點都直接或間接與終點連通。
在滿足條件 1 1的情況下使路徑最短。
注意:圖 GG 中可能存在重邊和自環,題目保證終點沒有出邊。

請你輸出符合條件的路徑的長度。

輸入輸出格式
輸入格式:

第一行有兩個用一個空格隔開的整數 nn 和 mm,表示圖有 nn 個點和 mm 條邊。

接下來的 mm 行每行 22 個整數 x,yx,y,之間用一個空格隔開,表示有一條邊從點 xx 指向點yy。

最後一行有兩個用一個空格隔開的整數 s, ts,t,表示起點為 ss,終點為 tt。

輸出格式:

輸出只有一行,包含一個整數,表示滿足題目描述的最短路徑的長度。如果這樣的路徑不存在,輸出-1−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
分析:題目要找出路徑上的所有點的出邊所指向的點都直接或間接與終點連通。也就是說當前點有一條邊的出邊最終沒有連到終點,那麼這個點就是不合條件的,標記不能通過這個點進行鬆弛。如樣例2

因為2的一條出邊指向6,而6最終沒有指向終點5,所以與2有關的邊不能作為鬆弛的點

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+10;
const int inf = 0x3f3f3f3f;
struct node{
    int v, w, nxt;
}edge[N];
int n, m, cnt, st, ed;
int fir[N], x[N], y[N], dis[N];
bool vis[N], book[N], book1[N];
inline void add(int u, int v, int w){
    edge[cnt] = (node){v, w, fir[u]};
    fir[u] = cnt++;
}
inline void dfs(int u){
    book[u] = true;
    for(int i = fir[u]; i; i = edge[i].nxt){
        int v = edge[i].v;
        if(!book[v])
            dfs(v);
    }
}
inline int spfa(int st){
    memset(vis, false, sizeof(vis));
    vis[st] = true;
    for(int  i = 1; i <= n; i++){
        dis[i] = inf;
    }
    dis[st] = 0;
    queue<int> Q;
    Q.push(st);
    while(!Q.empty()){
        int u = Q.front();
        Q.pop();
        vis[u] = true;
        for(int i = fir[u]; i; i = edge[i].nxt){
            int v = edge[i].v;
            if(book1[v]){
                continue;
            }
            if(dis[v] > dis[u] + edge[i].w){
                dis[v] = dis[u] + edge[i].w;
                if(!vis[v]){
                    vis[v] = false;
                    Q.push(v);
                }
            }
        }
    }
    return dis[ed];
}
int main(){
    #ifdef ONLINE_JUDGE
    #else
        freopen("in.txt", "r", stdin);
    #endif // ONLINE_JUDGE

    while(~scanf("%d%d", &n, &m)){
        cnt = 1;
        memset(fir, 0, sizeof(fir));
        memset(book, 0, sizeof(book));
        for(int i = 0; i < m; i++){
            scanf("%d%d", &x[i], &y[i]);
            add(y[i], x[i], 1);
        }
        scanf("%d%d", &st, &ed);
        dfs(ed);
        memset(fir, 0, sizeof(fir));
        for(int i = 0; i < m; i++){
            add(x[i], y[i], 1);
        }
        for(int i = 1; i <= n; i++){
            book1[i] = false;
            for(int j = fir[i]; j; j = edge[j].nxt){
                int v = edge[j].v;
                if(!book[v]){
                    book1[i] = true;
                    break;
                }
            }
        }
        int ans = spfa(st);
        if(ans == inf)
            printf("-1\n");
        else
            printf("%d\n", ans);
    }
    return 0;
}