单源最短路 T3

题目描述

P5767 [NOI1997] 最优乘车 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 最优乘车 - 洛谷 P5767 - Virtual Judge (csgrandeur.cn) H 城是一个旅游胜地,每年都有成千上万的人前来观光。为方便游客,巴士公司在各个旅游景点及宾馆,饭店等地都设置了巴士站并开通了一些单程巴士线路。每条单程巴士线路从某个巴士站出发,依次途经若干个巴士站,最终到达终点巴士站。

一名旅客最近到 H 城旅游,他很想去 S 公园游玩,但如果从他所在的饭店没有一路巴士可以直接到达 S 公园,则他可能要先乘某一路巴士坐几站,再下来换乘同一站台的另一路巴士,这样换乘几次后到达 S 公园。

现在用整数 给 H 城的所有的巴士站编号,约定这名旅客所在饭店的巴士站编号为 ,S 公园巴士站的编号为

写一个程序,帮助这名旅客寻找一个最优乘车方案,使他在从饭店乘车到 S 公园的过程中换车的次数最少。

输入格式

第一行有两个数字 ),表示开通了 条单程巴士线路,总共有 个车站。

从第二行到第 行依次给出了第 条到第 条巴士线路的信息。其中第 行给出的是第 条巴士线路的信息,从左至右按运行顺序依次给出了该线路上的所有站号相邻两个站号之间用一个空格隔开。

输出格式

只有一行。如果无法乘巴士从饭店到达 S公园,则输出 NO

否则输出你的程序所找到的最少换车次数,换车次数为 表示不需换车即可到达。

样例 #1

样例输入 #1

3 7
6 7
4 7 3 6
2 1 3 5

样例输出 #1

2

思路

可以把从当前点开始沿一条路线能走的点连一条边权为1的边, 这样只有在前往非当前路线的车站时, 才会将费用+1, 说明换乘了一次。

只需要在预处理时把该点之后的点都加条边即可。

代码

#include <iostream>
#include <cstring>
#include <algorithm>
#include <string>
#include <cmath>
#include <sstream>
using namespace std;
const int N = 5e2 + 1;
int n, m;
int g[N][N]; // 图
int bus[N];
int cnt[N];
int dist[N];
int q[N];
 
void bfs()
{
    memset(dist, 0x3f, sizeof dist);
    int hh = 0, tt = 0;
    q[0] = 1;
    dist[1] = 0;
    while (hh <= tt)
    {
        int t = q[hh++];
 
        if (t == n)
            return;
        for (int i = 1; i <= n; i++)
        {
            if (i == t || !g[t][i] || dist[i] <= dist[t])
                continue;
            dist[i] = dist[t] + g[t][i];
            q[++tt] = i;
        }
    }
}
 
int main()
{
    cin >> m >> n;
    string line;
    getline(cin, line);
    for (int i = 0; i < m; i++)
    {
        getline(cin, line);
        stringstream ssin(line);
        while (ssin >> bus[cnt[i]++])
            ;
        for (int j = 0; j < cnt[i]; j++)
            for (int k = j + 1; k < cnt[i]; k++)
                g[bus[j]][bus[k]] = 1;
    }
 
    bfs();
 
    if (dist[n] == 0x3f3f3f3f)
        cout << "NO\n";
    else
        cout << max(dist[n] - 1, 0) << endl;
    return 0;
}