题解 P2296 【寻找道路】

· · 题解

好不容易过了这道绿题,这道题卡了我几个月了

先说说思路吧

思路:

用一个vector存下每一条反向边,然后从终点开始bfs,能到达的点就用一个flag数组打个标记,这样便于之后搜索……

然后清空vector,将正向边存进去(注意要使用数组存边,这样才能正反存2次)……

接着我们查看每个点的出边所指向的点是否能到达终点,如果有一个达不到,用check数组标记(注意不能直接修改,会有后效性)

最后跑一遍dijkstra就好了,注意有输出-1的情况

上代码了

#include <cstdio>
#include <iostream>
#include <vector>
#include <queue>
#include <cstring>

using namespace std;

#define MAXN 10100
#define MAXM 201000
#define INF 0x3f3f3f3f

queue<int> que;//搜索用的队列
vector<int> vec[MAXN];//存边用的vector
int n, m, s, t;//题目所述
int x[MAXM], y[MAXM], dis[MAXN];//存边和dijkstra的数组
bool flag[MAXN], vis[MAXN], check[MAXN];//刚才讲过了,vis数组标记是否遍历过

void pre()//预处理每个点是否能到达终点
{
    que.push(t);
    vis[t] = flag[t] = 1;
    while (! que.empty())
    {
        int x = que.front();
        que.pop();
        for (int i = 0; i < vec[x].size(); ++ i)
        {
            int v = vec[x][i];
            if (vis[v])
                continue;
            flag[v] = vis[v] = 1;
            que.push(v);
        }
    }
    for (int i = 1; i <= n; ++ i)
        vec[i].clear();
    for (int i = 1; i <= m; ++ i)
        vec[x[i]].push_back(y[i]);
    for (int i = 1; i <= n; ++ i)//查看每个点出边指向的点能否到达终点
        for (int j = 0; j < vec[i].size(); ++ j)
            if (! flag[vec[i][j]])
            {
                check[i] = true;
                break;
            }
    for (int i = 1; i <= n; ++ i)
        flag[i] = (! check[i]);//标记
}

int bfs()
{
    memset(vis, 0, sizeof(vis));//注意再次搜索要清0
    for (int i = 1; i <= n; ++ i)
        dis[i] = INF;
    dis[s] = 0;
    vis[s] = 1;
    que.push(s);
    while (! que.empty())
    {
        int x = que.front();
        que.pop();
        vis[x] = false;
        for (int i = 0; i < vec[x].size(); ++ i)
        {
            int v = vec[x][i];
            if (dis[v] > dis[x] + 1 && flag[v])
            {
                dis[v] = dis[x] + 1;
                if (! vis[v])
                    que.push(v), vis[v] = 1;
            }
        }
    }
    return dis[t] == INF ? -1 : dis[t];//输出答案
}

int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= m; ++ i)//建反向边
    {
        scanf("%d%d", &x[i], &y[i]);
        if (x[i] == y[i])
            -- i, -- m;
        vec[y[i]].push_back(x[i]);
    }
    scanf("%d%d", &s, &t);
    pre();//预处理
    printf("%d", bfs());//输出
    return 0;
}