列表

详情


MT16. 公交车

描述

一座城市有 n 个公交站台,站点从 1 到 n 编号,和 m 班公交车,公交车从 1 到 m 编号,乘坐每班公交车只需花费 1 元钱,第 i 班公交车一共经过 ti 个站点,分别为站点 ai,1,ai,2,...,ai,ti,小明可以乘坐第 i 班公交车从这 ti  个站台中的任意一个到达任意一个站点,如一班公交车经过站点 1,2,3,那么小明花费 1 元钱就可以从 1 到 2 ,从 1 到 3 ,从 2 到 1,从 3 到 1,从3 到 2。
小明想从 1 号站台到 n 号站台,问他最少花费多少钱。

数据范围:

输入描述

第一行两个数 n , m。 接下来 m 行,依次描述公交车经过的站点,第 i 行开头一个数 t_i ,表示第 i 班公交车经过的站点数,接下来的 t_i 个数,依次表示这 t_i 个站点。

输出描述

输出一个数,从 1 号站点到 n 号站点的最小代价,如果不能达到则输出 -1。

示例1

输入:

5 3
3 1 2 3
3 3 4 2
3 3 5 4

输出:

2

说明:

先坐第一班公交车从 1 号到 3 号站点,再坐第三班公交车从 3 号站点到 5 号站点。

原站题解

C++ 解法, 执行用时: 29ms, 内存消耗: 7084KB, 提交时间: 2021-07-07

#include <bits/stdc++.h>
using namespace std;

int main() {
  int n = 0;// 站点数
  int m = 0;// 公交车数
  scanf("%d%d", &n, &m);
  int nums = n+m+2; // 图的节点数
  vector<int> vec[nums]; // 从1开始
  // 建图同一辆公交车通过的点建一条边到这辆公交车的抽象点,再从抽象点建一条边到这些点
  for (int i = 1; i <= m; i++) {
    int t = 0;
    scanf("%d", &t); // 公交车数经过站点数
    for (int j = 1; j <= t; j++) {
      int a = 0;
      scanf("%d", &a); // 公交车数经过站点
      vec[a].push_back(i+n); // 同一站点经过的公交车
      vec[i+n].push_back(a); // 同一辆公交车通过的站点
    }
  }
  queue<int> q;              // 定义队列
  int visited[nums];           // 定义标记顶点是否已访问
  fill_n(visited,nums,-1);   // 初始化为未访问
  visited[1] = 0;            // 标记v已经访问
  q.push(1);                 // 入队v
  while (!q.empty()) {       // 队列非空
    int now = q.front();     // 取出队首元素
    q.pop();                 // 队首元素出队
    for (int i = 0; i < vec[now].size(); i++) { // 遍历v的邻接点
      int post = vec[now][i];// 取出邻接点
      if (-1 == visited[post]) {  // 判断邻接点是否访问
        visited[post] = visited[now]+1;// 标记邻接点已访问
        q.push(post);        // 邻接点入队
      }
    }
  } 
  if(-1 == visited[n]) printf("-1\n");
  else printf("%d\n",visited[n]/2);
  return 0;
}

C++14 解法, 执行用时: 30ms, 内存消耗: 7036KB, 提交时间: 2019-04-27

#include <bits/stdc++.h>
using namespace std;

int main() {
  int n = 0;// 站点数
  int m = 0;// 公交车数
  scanf("%d%d", &n, &m);
  int nums = n+m+2; // 图的节点数
  vector<int> vec[nums]; // 从1开始
  // 建图同一辆公交车通过的点建一条边到这辆公交车的抽象点,再从抽象点建一条边到这些点
  for (int i = 1; i <= m; i++) {
    int t = 0;
    scanf("%d", &t); // 公交车数经过站点数
    for (int j = 1; j <= t; j++) {
      int a = 0;
      scanf("%d", &a); // 公交车数经过站点
      vec[a].push_back(i+n); // 同一站点经过的公交车
      vec[i+n].push_back(a); // 同一辆公交车通过的站点
    }
  }
  queue<int> q;              // 定义队列
  int visited[nums];           // 定义标记顶点是否已访问
  fill_n(visited,nums,-1);   // 初始化为未访问
  visited[1] = 0;            // 标记v已经访问
  q.push(1);                 // 入队v
  while (!q.empty()) {       // 队列非空
    int now = q.front();     // 取出队首元素
    q.pop();                 // 队首元素出队
    for (int i = 0; i < vec[now].size(); i++) { // 遍历v的邻接点
      int post = vec[now][i];// 取出邻接点
      if (-1 == visited[post]) {  // 判断邻接点是否访问
        visited[post] = visited[now]+1;// 标记邻接点已访问
        q.push(post);        // 邻接点入队
      }
    }
  } 
  if(-1 == visited[n]) printf("-1\n");
  else printf("%d\n",visited[n]/2);
}

上一题