ABC 132 | E - Hopscotch Addict

题目描述

给定一个无权有向图\(G\)(\(N\)个点,\(M\)条边),给定起点\(S\)和终点\(T\),问是否可以从\(S\)走到\(T\)。如果可以到达,输出最少步数;如果不能到达,输出-1
规定一步如下:沿\(G\)中边的指向走\(3\)条边记作一步

数据范围

  • \(2 \le N \le 10^5\)
  • \(0 \le M \le \min(10^5,N(N−1))\)

题解

  • 该题是一个分层图的典型问题,对于分层图问题,整体看上去是个bfs,之所以要分层,主要是考虑到状态表示和状态转移。
  • 比如该题要求的答案不是简单的\(dist[T]\),而是\(dist[T][0]\),不是从\(S\)\(T\)的最短路径的长度,而是从\(S\)\(T\)且长度\(\mod 3 = 0\)的最短路径的长度,输出的结果是\(dist[T][0] / 3\)
  • 即该题可以通过思考答案的表示上入手,而长度的记录本质上是个递推,类似于\(dp\)中的状态转移。

代码

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

using namespace std;

typedef pair<int, int> pii;

const int N = 1e5 + 10;

int h[N], e[N], ne[N], idx;
int n, m;
int st, ed;
int dist[N][10];

void add(int a, int b){
    e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}

void bfs(){
    memset(dist, 0x3f, sizeof dist);
    queue<pii> q;
    q.push({st, 0});
    dist[st][0] = 0;

    while(q.size()){
        auto t = q.front();
        q.pop();
        int ver = t.first, distance = t.second;
        for(int i = h[ver]; i != -1; i = ne[i]){
            int j = e[i];
            int k = (distance + 1) % 3;
            if(dist[j][k] > dist[ver][distance] + 1){
                dist[j][k] = dist[ver][distance] + 1;
                q.push({j, k});
            }
        }
    }
    return;
}

int main()
{
    scanf("%d%d", &n, &m);
    memset(h, -1, sizeof h);
    for(int i = 1; i <= m; i ++){
        int a, b;
        scanf("%d%d", &a, &b);
        add(a, b);
    }
    scanf("%d%d", &st, &ed);
    bfs();
    if(dist[ed][0] == 0x3f3f3f3f) puts("-1");
    else printf("%d\n", dist[ed][0] / 3);

    return 0;
}

posted @ 2022-06-12 16:02  小菜珠的成长之路  阅读(56)  评论(0)    收藏  举报